Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Работа цикла пока не нажата кнопка


Автор: Гость_Drizhenko 18.10.2005, 07:22
Помогите пожалуйста. Возникает задача создать цикл, который будет выполняться пока не нажата кнопка button2. То есть, что нужно поставить вместо точек? Или может организовать другой цикл, не while.

Код

while ...  do
  begin
    for i:=1 to 50 do
      begin
        memo1.Lines.Add(IntTostr(i));
        sleep(200);
      end;
  end;
end;


На форме две кнопки (button1 и button2). Первая запускает цикл, вторая остонавливает + memo1 для вывода на экран.

Код у меня не на C++, а не Delphi.

Автор: Zero 18.10.2005, 07:42
Цитата
Или может организовать другой цикл, не while.

А может, тогда тебе на форму кинуть таймер, и когда нажмёш кнопку, значение Enable присваивай false, и цикл остановится.
Цитата(Drizhenko @ 18.10.2005, 08:26)
Код у меня не на C++, а не Delphi.

В Билдере всё как в Delphi, поэтому разницы нету.
Добавлено @ 07:46
Вот пример:
Код

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  for (int i = 1; i<=50; i++)
    {
       Memo1->Lines->Add(i);
    };
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Timer1->Enabled = (Timer1->Enabled)?false: true;  //На одну кнопку можно и запускать и останавливать цикл...
}

Автор: Zero 18.10.2005, 08:27
А-а-а... блин, перепутал.... Если на делфи то, так:
Код

procedure TForm1.Timer1Timer(Sender: TObject);
var i:integer;
begin
  for i:=1 to 50 do
    memo1.Lines.Add(IntToStr(i));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Timer1.Enabled = false then
    Timer1.Enabled := true
  else Timer1.Enabled := false;
end;

А из за такой строки будут глюки:
Код

sleep(200);

Автор: Drizhenko 18.10.2005, 09:26
Интересное решение, но есть одно но. Когда я нажимаю кнопку, то таймер начинает работу, и в мемо вписываюся цифры и пока они не напишутся до 50 таймер не остнавится даже если я буду нажимать кнопку. А это неприемлимо, работа должна прикращаться ни когда выполнится цикл в любое время.
А вообще, спасибо за помощь.
Добавлено @ 09:31
Извиняюсь за граматические ошибки.

работа должна прикращаться ни тогда когда выполнится цикл, а в любое время.

Автор: Zero 18.10.2005, 09:48
Цитата(Drizhenko @ 18.10.2005, 10:26)
но есть одно но. Когда я нажимаю кнопку, то таймер начинает работу, и в мемо вписываюся цифры и пока они не напишутся до 50 таймер не остнавится даже если я буду нажимать кнопку. А это неприемлимо

Млин, ты же сам написал что должен прекращатся вот этот цикл:
Код

while ...  do

А этот:
Код

for i:=1 to 50 do
ясное дело не остановится...
Из-за вот этой строки:
Код

sleep(200);

Но если тебе нужно, просто выводить цифры от 1 до 50, периодически, а в нужное время останавливать, тогда можно сделать так:
Интервал таймера ставь 200 и коды такие:
Код

var
  Form1: TForm1;
  i:integer;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Timer1.Enabled then
    Timer1.Enabled := false
  else
    Timer1.Enabled := true;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if i>=51 then i:=1;
  memo1.Lines.Add(IntToStr(i));
  inc(i);
end;

Единственный недостаток, это то что тут переменная i обявлена как глобальная...

Автор: Drizhenko 18.10.2005, 10:06
Спасибо, работает.
А что означает функция inc(i). Я в Дельфи новичок.

Автор: Alexeis 18.10.2005, 10:06
Цитата
работа должна прикращаться ни тогда когда выполнится цикл, а в любое время


попробуй

Код

var
  Form1: TForm1;
  fl : Boolean = false;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  fl := true;
end;

..............
while not fl do
  begin
    for i:=1 to 50 do
      begin
        memo1.Lines.Add(IntTostr(i));
        application.processmessages;
     end;
  end;
.............





Автор: Zero 18.10.2005, 10:17
Цитата(Drizhenko @ 18.10.2005, 11:06)
А что означает функция inc(i). Я в Дельфи новичок.

Это альтенатива:
Код

i:=i+1;

Только
Код

inc(i);  
работает быстрее... Привычка у меня такая ставить её...
При инк, типа такого получается:
Код

Add i,1

Автор: Alexeis 18.10.2005, 10:17
inc(i); => i := i + 1;

Автор: YurikGL 18.10.2005, 22:02
Держи рабочий код

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Memo1: TMemo;
    Button1: TButton;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    i:integer;
    OutPutEnable,fl1:boolean;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
   i:=1;
   Timer1.Interval:=500;//Задержка между выводом символов
   fl1:=true;
   OutPutEnable:=false;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OutPutEnable then OutPutEnable:=false
                   else OutPutEnable:=true;
  while OutPutEnable do begin
    Memo1.Lines.add(IntToStr(i));
    inc(i);
    if i>50 then i:=1;
    fl1:=true;
    while fl1 do Application.ProcessMessages;
                        end;

end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  fl1:=false;
end;

end.

Автор: FRAGNATIC 18.10.2005, 22:41
да зачем таймеры то?
самый номаный вариант как уже предложил
alexeis1
Код

  fl : Boolean = false;    
implementation    
{$R *.dfm}    
procedure TForm1.Button1Click(Sender: TObject);    
begin    
  fl := true;    
end;    
..............    
while not fl do    
  begin    
    for i:=1 to 50 do    
      begin    
        memo1.Lines.Add(IntTostr(i));    
        application.processmessages;    
     end;    
  end;    
.............

Автор: Drizhenko 19.10.2005, 05:55
Цитата
procedure TForm1.Button1Click(Sender: TObject);
begin
  fl := true;
end;

Получается, что при нажатии кнопки f1 призваивается значение true, а цикл while начинает работу когда f1 ложно. То есть цикл никогда ни начнет работу. Если сделать так:
Код

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  i:integer;
  fl : Boolean = false;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

begin
  fl := false;

while not fl do
  begin
    for i:=1 to 50 do
      begin
        memo1.Lines.Add(IntTostr(i));
        application.processmessages;
     end;
  end;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  fl := true;
end;

end.

то все работает, но опять же цикл прекращает свою работу когда он переберёт все значения. НЕ ТО !!!!

Спасибо всем, остальное еще не попробовал.






Автор: Albinos_x 19.10.2005, 06:54
попробуй так:
Код

var    
  Form1: TForm1;    
  fl : Boolean = false;    
implementation    
{$R *.dfm}    
procedure TForm1.Timer1Timer(Sender: TObject);    
var i:integer;    
begin    
  for i:=1 to 50 do
    begin
     application.processmessages;
    If not Timer1.Enabled then Exit;    
    memo1.Lines.Add(IntToStr(i));
    end;    
end;    

procedure TForm1.Button1Click(Sender: TObject);    
begin    
  if Timer1.Enabled = false then
     begin
    Button1.Caption:='Остановить';    
    Timer1.Enabled := true
    end    
  else
  begin
 Timer1.Enabled := false;
  Button1.Caption:='Запустить'; 
  end;    
end;


Цитата
но опять же цикл прекращает свою работу когда он переберёт все значения. НЕ ТО !!!!

Конечно будет перебирать все значения у тебя.... у тебя нет проверки внутри цикла на выполнение условия останова, т.е. правильнее так:
Код

procedure TForm1.Button1Click(Sender: TObject);    
begin    
  fl := false;    
while not fl do    
  begin    
    for i:=1 to 50 do    
      begin    
        memo1.Lines.Add(IntTostr(i));    
        application.processmessages;
        If fl then Exit;    { выходим из процедуры, если просто нужно остановить цикл, допустим выполнить необходимые действия после цикла, то вместо Exit пишем Break}
     end;    
  end;    
end;

Автор: Alexeis 19.10.2005, 09:26
Вероятено
код будет работать если эту процедуру запустить отдельным
потоком, тогда реакция будет незамедлительной


Код

procedure TForm1.Button1Click(Sender: TObject);

begin
  fl := false;

while not fl do
  begin
    for i:=1 to 50 do
      begin
        //тут должна быть критическая секция
        memo1.Lines.Add(IntTostr(i));
        application.processmessages;
        If fl then Exit; //Как мне верно указали
     end;
  end;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 //тут должна быть критическая секция
  fl := true;
end;


Поправлено 13.00

Автор: Albinos_x 19.10.2005, 10:34
Цитата(alexeis1 @ 19.10.2005, 09:26)
while not fl do
  begin
    for i:=1 to 50 do
      begin
        //тут должна быть критическая секция
        memo1.Lines.Add(IntTostr(i));
        application.processmessages;
    end;
  end;


повторяете предыдущую ошибку, этот код не остановит цикл, я же писал:

Цитата(Albinos_x @ 19.10.2005, 06:54)
for i:=1 to 50 do   
      begin   
        memo1.Lines.Add(IntTostr(i));   
        application.processmessages;
        If fl then Exit;


Автор: Drizhenko 19.10.2005, 10:52
Цитата
//тут должна быть критическая секция

Извиняюсь за тупость, а что это значит???

Автор: YurikGL 21.10.2005, 20:11
Народ, что вы спорите... я написал программу и все проверил... Все работает

Цитата
Получается, что при нажатии кнопки f1 призваивается значение true, а цикл while начинает работу когда f1 ложно. То есть цикл никогда ни начнет работу. Если сделать так:

fl1 сбрасывается таймером и цикл прекращается

цикл while OutPutEnable do тоже не бесконечен т.к. при повторном нажатии на кнопку переменная OutPutEnable будет инвертирована и цикл прекратится.

Цитата
да зачем таймеры то?

Что-бы делать задержку между выводом символов.

Короче, код рабочий. Прерывание происходит незамедлительно.

Кстати, его можно еще слегка оптимизировать

Код


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Button1: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    fl1:boolean;
    i:integer;

    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
   i:=1;
   Timer1.Interval:=500;//Задержка между выводом символов
   Timer1.enabled:=false;
   fl1:=true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Timer1.Enabled then Timer1.Enabled:=false
                    else Timer1.Enabled:=true;
  while Timer1.Enabled do begin
    Memo1.Lines.add(IntToStr(i));
    inc(i);
    if i>50 then i:=1;
    fl1:=true;
    while fl1 do Application.ProcessMessages;
                        end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
fl1:=false;
end;

end.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)