Предотвратить повторное нажатие кнопки (без потоков)
Есть кнопка, по щелчку на ней выполняется цикл и увеличивается значение счетчика в TEdit. Если пользователь нажимает кнопку второй раз, до того как завершилось выполнение первого вызова функции, то, соответственно, счетчик увеличится еще на единицу. Нужно сделать, чтобы пока не завершится вызов первой функции - вторая не вызывалась. Возможно это сделать без использования потоков?
P.S.
Первое же, что пришло в голову - использование глобальной переменной. Выставляем 1 при первом запуске и 0 после его завершения. Пока стоит 1 - второй вызов функции прерываем. Но получается, что второй вызов функции помещается в очередь и стартует уже после того, как завершен первый, т.е. значение переменной во время второго вызова равно 0 и нажатие все равно обрабатывается.
Надо сразу после этого прокачать очередь сообщений - чтобы они обработались.
В винформах это Application.DoEvents()
или Refresh() этому контролу....
что-то аналогичное должно быть и в дельфи.
Сделайте замедлитель. после нажатия - деактивируйте конопку, и запустите таймер, на полсекунды - чтобы он ее разморозил. Но это мне, как пользователю, было бы неприятно. А если я вот хочу быстро-быстро нащелкать счетчик?
:-)
Т.е. как я понимаю в начале процедуры сделать кнопку неактивной, а в конце процедуры вставить строку "Timer1.Enabled := True;" и уже в процедуре самого таймера "Button1.Enabled := True; Timer1.Enabled := False"? Блин... Я аплодирую стоя! Конечно над внедрением такого алгоритма еще стоит подумать, но вот сама идея - гениальна ))).
Думаю все-таки это не совсем то, что я имел ввиду. Вопрос остается открытым.
Хотите очередь сообщений чистить? А разве делать кнопку неактивной - это не то же самое?
Цитата: proc
Ха! Вот это да! Мне бы в голову не пришло )))
Т.е. как я понимаю в начале процедуры сделать кнопку неактивной, а в конце процедуры вставить строку "Timer1.Enabled := True;" и уже в процедуре самого таймера "Button1.Enabled := True; Timer1.Enabled := False"? Блин... Я аплодирую стоя! Конечно над внедрением такого алгоритма еще стоит подумать, но вот сама идея - гениальна ))).
Думаю все-таки это не совсем то, что я имел ввиду. Вопрос остается открытым.
Т.е. как я понимаю в начале процедуры сделать кнопку неактивной, а в конце процедуры вставить строку "Timer1.Enabled := True;" и уже в процедуре самого таймера "Button1.Enabled := True; Timer1.Enabled := False"? Блин... Я аплодирую стоя! Конечно над внедрением такого алгоритма еще стоит подумать, но вот сама идея - гениальна ))).
Думаю все-таки это не совсем то, что я имел ввиду. Вопрос остается открытым.
если самое простое решение - то делать кнопку неактивной в начале процедуры, и активировать в конце. И просто и эффективно
Если кнопку при первом запуске сделать неактивной - и в конце процедуры не выставлять Enabled в True, т.е. оставлять ее неактивной, то щелчки не обрабатываются. Вот поэтому я и делаю вывод, что в то время, пока кнопка неактивна и процедура выполняется, приложение все равно запоминает действия пользователя для кнопки, помещая их в очередь, и выполняет после того, как в конце процедуры мы вновь делаем кнопку активной.
Вот код, срабатывающий по нажатию кнопки:
procedure TfrmProp.btnGetBruttoClick(Sender: TObject);
var
Weight, StepWeight:double;
// Украшательства ради
//==================================================
// i:integer;
// Step:double;
// SWeight:double;
//==================================================
begin
frmProp.btnGetBrutto.Enabled := False;
// Защита от "дребезга"
if GetTickCount - frmProp.LastClick < CONTACT_NOISE_PROTECTION then exit
else frmProp.LastClick:= GetTickCount;
Weight:= Data.CurList.FieldByName('BRUTTO').AsFloat;
if ( Weight <> 0 ) and ( frmProp.AxesCount = 0 ) then begin
Weight:= 0;
Data.CurList.FieldByName('AXES_BRUTTO').AsString:= '';
end;
// Украшательства ради
//==================================================
// SWeight:= Weight;
//==================================================
StepWeight:= frmProp.GetWeight;
Weight:= Weight+StepWeight;
inc(frmProp.AxesCount);
Data.CurList.FieldByName('BRUTTO').AsFloat:= Weight;
Data.CurList.FieldByName('BRUTTO').AsString:= Data.CurList.FieldByName('BRUTTO').DisplayText;
if frmProp.AxesCount = 1 then
Data.CurList.FieldByName('AXES_BRUTTO').AsString:= Data.CurList.FieldByName('BRUTTO').AsString
else
Data.CurList.FieldByName('AXES_BRUTTO').AsString:= Data.CurList.FieldByName('AXES_BRUTTO').AsString + ', ' +
Format('%.1f', [StepWeight]);
// Украшательства ради
// Украшательство заключается в том, что
// Индикатор как бы постепенно "нарастает"
//==================================================
// Step:= (Weight-SWeight)/10;
// for i:= 1 to 10 do begin
// SWeight:= SWeight + Step;
// pnBrutto.Caption:= Format('%.1f', [SWeight]);
// Application.ProcessMessages;
// Sleep(30);
// end;
//==================================================
frmProp.pnBrutto.Caption:= Format('%.1f', [Data.CurList.FieldByName('BRUTTO').AsFloat]);
frmProp.pnAxes.Caption:= IntToStr(frmProp.AxesCount);
frmProp.LastWeight:= Weight;
frmProp.pnLastWeight.Caption:= Format('%.1f', [frmProp.LastWeight]);
frmProp.btnGetBrutto.Enabled := True;
end;
Вот код функции, которая вызывается внутри обработчика нажатия кнопки и имитирует какой-то процесс:
function TfrmProp.GetWeight: double;
begin
Result:= 12.4;
sleep(4000);
exit;
end;
Собственно все... Не могу понять - в чем дело. Скорее всего где-то что-то не доглядел.
frmProp.pnBrutto.Caption:= Format('%.1f', [Data.CurList.FieldByName('BRUTTO').AsFloat]);
frmProp.pnAxes.Caption:= IntToStr(frmProp.AxesCount);
frmProp.LastWeight:= Weight;
frmProp.pnLastWeight.Caption:= Format('%.1f', [frmProp.LastWeight]);
Application.ProcessMessages;
frmProp.btnGetBrutto.Enabled := True;
end;
Можно было поставить Application.ProcessMessages сразу после frmProp.btnGetBrutto.Enabled:=False,чтобы сообщения просто не генерировались(потому как кнопка будет заблокирована)