Chertenok.ru - все о программировании
Вход  |  Регистрация  |  Поиск 
Праздник
Через 3 дня :

День славянской письменности и культуры


Как выйти из цикла по Ctrl+C


Новая тема  Ответить  Печать Предыдущая тема  Следующая тема
Автор Сообщение
Пол:Муж KVas
Новичок


Возраст: 46
Знак зодиака: Скорпион
Зарегистрирован: 26.08.2008
Сообщения: 17

СообщениеПт, 25-Дек-2009 12:18    Заголовок сообщения: Как выйти из цикла по Ctrl+C
Цитата

Здравствуйте! Мне нужно реализовать досрочный выход из цикла Repeat .. Until по нажатию, например Ctrl+C. Проблема в том, как отследить, что нажатие было? В свойствах формы устанавливал KeyPreview=True и обрабатывал событие OnKeyPress формы. Все работает до того, как начинается цикл, внутри цикла программа отказывается ловить нажатия на клавиши (и щелчки мышки тоже). Пробовал sleep(100) – не помогает. Еще пробовал вынести цикл в отдельный поток, проблема с Ctrl+C решается, но там не работает вызов хранимой процедуры (компоненты FIBPlus). Можно ли как-то решить эту проблемку?
В начало
Посмотреть профиль Отправить личное сообщение
Hunter
Энтузиаст




Зарегистрирован: 14.09.2006
Сообщения: 349

СообщениеПт, 25-Дек-2009 12:43 
Цитата

Цитата:
Еще пробовал вынести цикл в отдельный поток, проблема с Ctrl+C решается, но там не работает вызов хранимой процедуры (компоненты FIBPlus).


Это правильное направление, рекомендую все-таки разобраться.

Есть еще классический способ, добавить в цикл вызов Application.ProcessMessages(), но вариант с циклом в отдельном потоке лучше.
В начало
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Пол:Муж KVas
Новичок


Возраст: 46
Знак зодиака: Скорпион
Зарегистрирован: 26.08.2008
Сообщения: 17

СообщениеПт, 25-Дек-2009 16:00 
Цитата

Hunter писал(а):

Это правильное направление, рекомендую все-таки разобраться.

при попытке выполнения fmProc.Query.ExecProcedure('NameProc') изнутри потока выдает

Какая-то системная ошибка мешает выполнению - это можно как-то побороть?


Последний раз редактировалось: KVas (Ср, 30-Дек-2009 10:39), всего редактировалось 1 раз
В начало
Посмотреть профиль Отправить личное сообщение
Пол:Муж Шурик
Я живу тут....


Возраст: 42
Знак зодиака: Овен
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
СообщениеПт, 25-Дек-2009 16:40 
Цитата

Цитата:
Мне нужно реализовать досрочный выход из цикла Repeat .. Until по нажатию, например Ctrl+C. Проблема в том, как отследить, что нажатие было?

delphi:
  1. function KeyPressed( VK_Value: Integer ): Boolean;
  2. begin
  3.  Result := GetKeyState( VK_Value ) < 0 ;
  4. end;
  5.  
  6. repeat
  7.   ...
  8.   if KeyPressed( VK_Control ) and KeyPressed( Ord('C') ) then Break;
  9.   ...
  10. until ...


Цитата:
В свойствах формы устанавливал KeyPreview=True и обрабатывал событие OnKeyPress формы. Все работает до того, как начинается цикл, внутри цикла программа отказывается ловить нажатия на клавиши (и щелчки мышки тоже).

OnKeyPress определяет, что будут вызываться события формы OnKeyXxxx. Но любые события вызываются "раздельно" – пока обрабатывается одно (с твоим циклом) другое не вызовется. Чтобы OnKeyDown фомы могло вызваться вставь в цикл вызов Application.ProcessMessages. Эта функция будет выполнять обработку накопившихся системных сообщений. В OnKeyDown ставишь флажок; после Application.ProcessMessages проверяешь его.

Цитата:
Еще пробовал вынести цикл в отдельный поток, проблема с Ctrl+C решается, но там не работает вызов хранимой процедуры

Потоки – вещь хорошая. Но есть нюансы с обращением к визуальным элементам из потока. Если таковые есть, их нужно оформлять процедурой и вызывать через Synchronize. Может в этом причина ошибки? Вообще-то компонент невизуальный, но мало ли... Что такое fmQuery в сообщении об ошибке? Случайно не форма?

_________________
Ответ готов, готов ли твой вопрос?
В начало
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
Пол:Муж KVas
Новичок


Возраст: 46
Знак зодиака: Скорпион
Зарегистрирован: 26.08.2008
Сообщения: 17

СообщениеПт, 25-Дек-2009 17:50 
Цитата

Шурик писал(а):

delphi:
  1. function KeyPressed( VK_Value: Integer ): Boolean;
  2. begin
  3.  Result := GetKeyState( VK_Value ) < 0 ;
  4. end;
  5.  

KeyPressed почему-то не сработало, а вот Application.ProcessMessages самое то и есть, очень большое спасибо за оперативный компетентный ответ.
Цитата:
Что такое fmQuery в сообщении об ошибке? Случайно не форма?

Да - fmProc это отдельная форма, на которой расположены общие процедуры и FIB компоненты доступа к БД, в том числе и Query (клас TpFIBQuery).
Еще раз большое спасибо, уже не первый раз меня выручаете.
В начало
Посмотреть профиль Отправить личное сообщение
Пол:Муж Шурик
Я живу тут....


Возраст: 42
Знак зодиака: Овен
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
СообщениеПт, 25-Дек-2009 18:07 
Цитата

Цитата:
KeyPressed почему-то не сработало

А что именно?
Просто интересно... Это рабочая процедура, которую я сам использую.

Цитата:
Да - fmProc это отдельная форма

Возможно в этом причина. Смешивать формы с потоками нужно осторожно.

Добавлено спустя 5 минут 39 секунд:

Использование Application.ProcessMessages имеет ещё один эффект, обычно полезный. Если по нажатию на кнопку, меню и т.п. ты выполняешь процедуру, занимающую много времени, пользовательский интерфейс "замерзает" – не реагирует ни на что. Дело в том, что визуальный интерфейс "живёт" за счёт обработки событий, которые система шлёт приложению - движения мыши, нажатия. Но они в пределах приложения выполняются последовательно, не прерывая друг друга. Выполняя Application.ProcessMessages в "длинной" процедуре ты инициируешь обработку накопившихся сообщений и это "оживляет" интерфейс.

_________________
Ответ готов, готов ли твой вопрос?
В начало
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
Hunter
Энтузиаст




Зарегистрирован: 14.09.2006
Сообщения: 349

СообщениеПт, 25-Дек-2009 18:38 
Цитата

... но с другой стороны, если часто вызывать ProcessMessages() в "коротких" циклах, то это создает излишнюю нагрузку на процессор, а также замедляет выполнение цикла. Можно пойти на компромисс, и вызывать ProcessMessages() не каждый цикл, а каждые N циклов.
В начало
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Пол:Муж Шурик
Я живу тут....


Возраст: 42
Знак зодиака: Овен
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
СообщениеПт, 25-Дек-2009 19:05 
Цитата

Цитата:
если часто вызывать ProcessMessages() в "коротких" циклах, то это создает излишнюю нагрузку на процессор

Ну да. Я обычно пишу что-то типа такого:

delphi:
  1. for i:=1 to SomeCount do
  2. begin
  3.   ...
  4.   if (i mod 1000) = 0 then
  5.       Application.ProcessMessages;
  6.   ...
  7. end;

Через сколько итераций цикла вызывать ProcessMessages – зависит от логики конкретного цикла. Где-то это 100, где-то 1000 или 10000.

_________________
Ответ готов, готов ли твой вопрос?
В начало
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
Пол:Муж KVas
Новичок


Возраст: 46
Знак зодиака: Скорпион
Зарегистрирован: 26.08.2008
Сообщения: 17

СообщениеСр, 30-Дек-2009 10:38 
Цитата

Извините не сразу ответил, думал тема закрыта
Шурик писал(а):

А что именно?
Просто интересно... Это рабочая процедура, которую я сам использую.

Функцию разместил в разделе описания переменных той же процедуры, где цикл, для удобства отладки код записал в таком виде.
delphi:
  1.      
  2.       k_p1:=KeyPressed( VK_Control );
  3.       k_p2:=KeyPressed( Ord('C') );
  4.       if k_p1 and k_p2 then Break;
  5.  

и k_p1, и k_p2 возвращают False независимо от того, нажимал я Ctrl+C или нет. Может функцию в каком другом месте нужно описать?

Цитата:
Выполняя Application.ProcessMessages в "длинной" процедуре ты инициируешь обработку накопившихся сообщений и это "оживляет" интерфейс.

О-очень приятный "побочный" эффект. Решал эту проблему через sleep(100), но не всегда нормально работало.
В начало
Посмотреть профиль Отправить личное сообщение
Пол:Муж Шурик
Я живу тут....


Возраст: 42
Знак зодиака: Овен
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
СообщениеСб, 02-Янв-2010 16:14 
Цитата

Цитата:
k_p1, и k_p2 возвращают False независимо от того, нажимал я Ctrl+C или нет

"Нажимал"... Функция KeyPressed проверяет нажата ли клавиша в данный момент. Скорее всего у тебя интервал между проверками достаточно большой; нажатие клавиши происходит между проверками; выходит, что в момент проверки ничего не нажато. Если ты попробуешь, подержишь Ctrl+C нажатыми подольше, думаю KeyPressed их "заметит".
С этой точки зрения для тебя более предпочтителен вариант с событиями и Application.ProcessMessages. События генерируются по каждому нажатию кнопки и ждут в очереди, когда их обработают. Т.е. как редко бы ты не проверял после нажатия кнопки по ProcessMessages ты получишь её из очереди событий.

Цитата:
Может функцию в каком другом месте нужно описать?

Если компилятор её видит – разместил правильно :)

_________________
Ответ готов, готов ли твой вопрос?
В начало
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
Показать сообщения:   
Страница 1 из 1
Перейти:  
Новая тема  Ответить  Печать

Вы можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете присоединять файлы в этом форуме
Вы можете скачивать файлы в этом форуме
хостинг от .masterhost 
Rambler's Top100