Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Как прекратить выполнение события из продцедуры?  [new]
InterSky
Member

Откуда:
Сообщений: 575
Произошло какое-то событие, ну допустим OnButton.Click, и оно выполняется...
Если в теле этого события встретится Exit, то выполнение прекращается.
Но если, в нём вызывается процедура, и уже в ней встретится Exit, то прекратится исполнение только этой процедуры. А можно ли из процедуры остановить выполнение всего события?

Конечно можно делать костыли: можно превратить процедуру в функцию, и в ней перед выходом подавать значение: выполнилась нормально или прекратила работу через Exit, а потом на основания полученного от функции значения делать такой же выход и в блоке вызвавшем функцию. Но это костыли! Возможно тут кто-то возмущённо скажет, что НЕТ, что Именно так и должна работать программа, последовательно и продуманно выполняя каждое действие... Но по такой логике и Exit не должен существовать, а тем более ужасный Halt.

Ну или как аналог взять циклы: там есть Continue (так же как Exit прерывающий выполнение блока), но есть и Break - который прекращает выполнение всего цикла (вот аналог такого для прекращения события я и ищу).

P.S. Предвижу что кто-то вместо решения задачи, будет говорить о лени, о том что дескать поставить одну проверку, или даже вписать вместо простого вызова процедуры, конструкцию типа: if MyFunction=666 then Exit - это даже красиво... Но эти процедура приводящая к остановке может иметь и десятую степень вложенности, и тогда переделывать процедуры в функции надо будет в десятках мест. Да и где-то может оказаться что остановка произойдёт в функции, а она уже и так что-то возвращает...
Тут сразу же появятся люди которые предложат проверять не возвращаемое событие, а специально созданную глобальную переменную. И по всему коду, на всех уровнях вложенности, после выхода из каждой процедуры или функции связанной с этим событием надо будет выставлять проверки выхода (если внутри могла быть изменена эта глобальная переменная).

Тут уже кто-то ужаснётся - Что так у тебя за монстр, многоуровневый и остановить которого может потребоваться не в одном каком-то месте, а во многих местах на разных уровнях?
Всё просто: Одна кнопка, и она вызывает событие который производит анализ большого массива данных. Расчёты производятся десятками разных методов. У каждого разный метод. Где-то идём рекурсивно, где-то проверяем на возможность ошибок перебором углубляясь вглубь и сравнивая с другими блоками массива, где-то пытаемся вычислить что может произойти и просчитываем дальнейшие решения на базе имеющихся данных, чтобы предугадать события, где-то просто оптимизируем меняя одну последовательно данных на другую... И на разных уровнях вложенности есть возможность отображения на экране (изменение данных, изменение данных, отметка области с ошибками, удаление того что не повлияет ни на что... Всем выводом занимается одна процедура (вызываемая из сотни мест на разных уровнях вложенности процедур и функций). И чтобы сделать пошаговый вывод, достаточно было бы в конце этой функции вызвать какой-то условный GlobalExit (или EventExit), который бы остановил всё действие единственного события. Чтобы оператор проанализировал изменения, и принял решение о продолжении анализа уже с другими параметрами или с другим приоритетом или в другом направлении. Не хочется в случае пошагового режима после каждого вывода данных делать бесконечный цикл (таким образом останавливая работу программы) и Halt'ить её для того чтобы оператор продолжил анализ с другими параметрами.
9 сен 19, 13:56    [21966830]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Aniskin
Member

Откуда:
Сообщений: 320
type
  EEverythingIsOk = class(Exception);

procedure Job;
begin
  // Some code
  if SomeCondition then 
    raise EEverythingIsOk.Create(''); // вместо Exit
  // Some code
end;

procedure TForm6.btn1Click(Sender: TObject);
begin
  try
    Job;
  except
    on E: EEverythingIsOk do
    else raise;
  end;
end;
9 сен 19, 14:11    [21966849]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48594

Aniskin
raise EEverythingIsOk

Обычно используется Abort;

Posted via ActualForum NNTP Server 1.5

9 сен 19, 14:14    [21966854]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26125
InterSky
А можно ли из процедуры остановить выполнение всего события?

Можно процедуру объявить функцией и анализировать её результат.
9 сен 19, 14:48    [21966908]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
InterSky
Member

Откуда:
Сообщений: 575
wadman
InterSky
А можно ли из процедуры остановить выполнение всего события?

Можно процедуру объявить функцией и анализировать её результат.

Процедура которую вы предложили объявить функцией и анализировать её результат, сама может быть вызвана из другой функции вызванной из процедуры сработавшей по OnClick. Этот вариант предусмотрительно разобран в вопросе, чтобы заранее избавиться от ответов типа вашего...

Aniskin - спасибо!
9 сен 19, 15:19    [21966955]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
goldmi45
Member

Откуда:
Сообщений: 1193
InterSky, обработка исключительных ситуаций может вам помочь.
InterSky
...
Ну или как аналог взять циклы: там есть Continue (так же как Exit прерывающий выполнение блока), но есть и Break - который прекращает выполнение всего цикла (вот аналог такого для прекращения события я и ищу).


Break прерывает цикл, но не прерывает процедуру. Exit - прерывает не только цикл, но и процедуру.
9 сен 19, 15:30    [21966964]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Dimitry Sibiryakov
Обычно используется Abort;
+1
9 сен 19, 15:35    [21966975]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
InterSky
Member

Откуда:
Сообщений: 575
goldmi45
InterSky, обработка исключительных ситуаций может вам помочь.
InterSky
...
Ну или как аналог взять циклы: там есть Continue (так же как Exit прерывающий выполнение блока), но есть и Break - который прекращает выполнение всего цикла (вот аналог такого для прекращения события я и ищу).


Break прерывает цикл, но не прерывает процедуру. Exit - прерывает не только цикл, но и процедуру.

Вы знаете что такое аналогия?
Представьте язык программирования, в котором нету циклов (а так же goto и рекурсии). Если вам надо было бы что-то выполнить в цикле от 1 до 5, вы бы писали:
procedure outerProc;

 Procedure innerProc(const n : Integer);
 begin
 // Тут пишется то что вы писали бы в теле цикла.
 end;

begin
innerProc(1);
innerProc(2);
innerProc(3);
innerProc(4);
innerProc(5);
end;


То есть, цикл - это процедура внутри процедуры.
Если вместо комментария вы впишите текст программы и там встретится Exit, он сработает как Continue в циклах и завершит лишь внутреннюю процедуру "innerProc". По аналогии, встречающийся в цикле Break завершил бы внешнюю процедуру "outerProc".
9 сен 19, 17:07    [21967087]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
ёёёёё
Member

Откуда:
Сообщений: 1274
InterSky,

"Выдыхай, бобер" - ©.
9 сен 19, 17:22    [21967100]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 3389
InterSky,

автор
Но если, в нём вызывается процедура, и уже в ней встретится Exit, то прекратится исполнение только этой процедуры. А можно ли из процедуры остановить выполнение всего события?


надежнее и проще всего решается исключениями
9 сен 19, 18:10    [21967159]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Есть еще более красивый вариант:


function MyProc: boolean;
begin
//
  if something then Exit(False);
//
end;


procedure Main;
begin
  If not MyProc then Exit;
end;
9 сен 19, 18:15    [21967164]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
InterSky
Member

Откуда:
Сообщений: 575
rgreat
Есть еще более красивый вариант:

If not MyProc then Exit;

Я же объяснил что и из функций тоже надо выходить...
9 сен 19, 18:25    [21967175]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
InterSky,

Меняйте функцию.

funtion myFunc: integer;
на
funtion myFunc(out Res: integer): boolean;
9 сен 19, 18:29    [21967178]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Собственно половина winAPI так работает.
9 сен 19, 18:30    [21967179]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48594

InterSky
Я же объяснил что и из функций тоже надо выходить...

Слово "аборт" ты при чтении топика пропустил как "шибка нипанятное"?

Posted via ActualForum NNTP Server 1.5

9 сен 19, 18:35    [21967183]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Dimitry Sibiryakov,

Abort - медленно.
Если таких выходов предпологается много - это очень плохое решение.

Как-то у меня коллега сделал как-то так:
function IsFloat(Text: string): boolean
begin
   try
      StrToFloat(Text);
      Result:=True;
   except
      Result:=False;
   end;
end;

А потом удивлялся, что это у него все тормозит нещадно на больших объемах данных.
9 сен 19, 18:40    [21967186]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48594

rgreat
А потом удивлялся, что это у него все тормозит нещадно на больших объемах данных.

Тормозило у него в основном из-за передачи строки по значению скорее всего. SEH,
используемый для исключений, считается быстрейшим способом их обработки из всех.

Posted via ActualForum NNTP Server 1.5

9 сен 19, 18:46    [21967191]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Dimitry Sibiryakov,

function IsFloat(const Text: string): boolean;
begin
   try
      StrToFloat(Text);
      Result:=True;
   except
      Result:=False;
   end;
end;

var
  i : integer;
  c : cardinal;
begin
  c:=getTickCount;
  for i:=0 to 1000 do begin
    IsFloat('2354fvbcv');
  end;
  writeln(getTickCount-c);
  c:=getTickCount;
  for i:=0 to 1000 do begin
    StrToFloatDef('2354fvbcv',0);
  end;
  writeln(getTickCount-c);


11297
0
9 сен 19, 18:52    [21967200]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48594

rgreat
11297
0

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

Posted via ActualForum NNTP Server 1.5

9 сен 19, 19:07    [21967211]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Dimitry Sibiryakov,

0.1 секунды на мнеджер памяти не списать.

Если бы дело было только в нем то было бы не 100 вызовов в секунду а как минимум 10000.
9 сен 19, 19:21    [21967221]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Упс, 0.01 сек. Опечатался.
9 сен 19, 19:22    [21967222]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48594

rgreat
0.1 секунды на мнеджер памяти не списать.

Это у тебя что-то с таймером. Мне пришлось добавить два нуля в цикл чтобы получить
4087
47

Posted via ActualForum NNTP Server 1.5

9 сен 19, 19:23    [21967223]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
Василий 2
Member

Откуда:
Сообщений: 792
Выброс исключения тормозит, да. Там, где предполагается частый отрицательный результат, лучше юзать возврат флага/кода ошибки
9 сен 19, 19:26    [21967225]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Dimitry Sibiryakov
Это у тебя что-то с таймером.

Не, реально 11 секунд.

Delphi 10.2, Release, Core i5-6500 3.2 GHz.
9 сен 19, 19:28    [21967227]     Ответить | Цитировать Сообщить модератору
 Re: Как прекратить выполнение события из продцедуры?  [new]
rgreat
Member

Откуда:
Сообщений: 5441
Под x64 быстрей.

x86 - 11391
х64 - 4265
9 сен 19, 19:31    [21967229]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить