Почему в этом случае TButton.enable не дает ожидаемого результата?

В приложении FireMonkey (Delphi XE3) происходит следующее. Посмотрите на следующий код (это просто фиктивный пример, чтобы проиллюстрировать проблему):

procedure TForm1.Button4Click(Sender: TObject);
var
    i: Integer;
begin
    Button4.Enabled:= false; //This should gray-out the button

    // get busy for some time
    for I := 0 to 100000000000 do
    begin

    end;

    Button4.Enabled:= true;
end;

Я ожидал, что Button4 станет неактивным перед входом в занятую операцию, представленную циклом «for». Тем не менее, это не так.

К концу выполнения обработчика OnClick кнопка «как бы не реагирует» на Button4.Enabled:= false. Почему?

Как я могу обойти это?

Это прекрасно работает в VCL.

Спасибо.


person Yanniel    schedule 04.07.2013    source источник
comment
MainThread предназначен только для задач пользовательского интерфейса, а не для длительных расчетных задач. Это должно быть сделано в фоновой задаче. Отключите кнопку запуска фоновой задачи и включите ее, когда фоновая задача будет завершена.   -  person Sir Rufo    schedule 04.07.2013


Ответы (1)


Это не реакция, потому что реакция видна только тогда, когда кнопка перерисовывается. Это происходит только тогда, когда обрабатывается следующее сообщение wm_Paint, но ваш код не обрабатывает сообщения, поэтому кнопка и вся форма остаются неизменными на протяжении всего цикла.

Немедленным исправлением будет вызов Button4.Repaint, что позволит кнопке обновить свой внешний вид. Однако это не обрабатывает все сообщения.

Плохим решением было бы время от времени вызывать Application.ProcessMessages в вашем цикле, но потребность в этом вызове обычно является признаком того, что вы делаете что-то неправильно.

Наконец, лучшим решением было бы переместить вашу длительную задачу в другой поток. Отключите кнопку при запуске задачи и включите ее после завершения задачи.

person Rob Kennedy    schedule 04.07.2013
comment
Роб, нет метода обновления для элементов управления FMX? - person Jason; 04.07.2013
comment
Ты спрашиваешь меня или говоришь мне, @Jason? Похоже, в Fire Monkey такого метода нет. Однако есть Repaint, который работает и в VCL. Это синоним обновления. - person Rob Kennedy; 04.07.2013
comment
ну, я не смог найти его - метод обновления - поэтому просто разместил его, не делая общего заявления на случай, если я ошибаюсь. FWIW, я только что протестировал использование Repaint, и это не сработало для меня, тогда как Application.ProcessMessages работает, поэтому это может быть немного сложнее для элементов управления, связанных с FMX. - person Jason; 04.07.2013
comment
Вызов Button4.Repaint не имеет никакого значения. Это была одна из первых вещей, которые я попробовал, и я забыл упомянуть об этом, когда задавал вопрос. Простите за это. Application.ProcessMessages решает проблему, но мне это тоже не нравится. Попробую многопоточность. Спасибо, парни. - person Yanniel; 04.07.2013