| Автор
| Сообщение |
 KVas
Новичок

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

Зарегистрирован: 14.09.2006
Сообщения: 349
|
|
|
Цитата |
|
| Цитата: | | Еще пробовал вынести цикл в отдельный поток, проблема с Ctrl+C решается, но там не работает вызов хранимой процедуры (компоненты FIBPlus). |
Это правильное направление, рекомендую все-таки разобраться.
Есть еще классический способ, добавить в цикл вызов Application.ProcessMessages(), но вариант с циклом в отдельном потоке лучше. |
|
| В начало |
|
 |
 KVas
Новичок

Возраст: 46
Знак зодиака: 
Зарегистрирован: 26.08.2008
Сообщения: 17
|
|
|
Цитата |
|
| Hunter писал(а): |
Это правильное направление, рекомендую все-таки разобраться. |
при попытке выполнения fmProc.Query.ExecProcedure('NameProc') изнутри потока выдает
Какая-то системная ошибка мешает выполнению - это можно как-то побороть?
Последний раз редактировалось: KVas (Ср, 30-Дек-2009 10:39), всего редактировалось 1 раз |
|
| В начало |
|
 |
 Шурик
Я живу тут....

Возраст: 42
Знак зодиака: 
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
|
|
|
Цитата |
|
| Цитата: | | Мне нужно реализовать досрочный выход из цикла Repeat .. Until по нажатию, например Ctrl+C. Проблема в том, как отследить, что нажатие было? |
| delphi: | function KeyPressed( VK_Value: Integer ): Boolean; begin Result := GetKeyState( VK_Value ) < 0 ; end; repeat ... if KeyPressed( VK_Control ) and KeyPressed( Ord('C') ) then Break; ... until ...
|
| Цитата: | | В свойствах формы устанавливал KeyPreview=True и обрабатывал событие OnKeyPress формы. Все работает до того, как начинается цикл, внутри цикла программа отказывается ловить нажатия на клавиши (и щелчки мышки тоже). |
OnKeyPress определяет, что будут вызываться события формы OnKeyXxxx. Но любые события вызываются "раздельно" – пока обрабатывается одно (с твоим циклом) другое не вызовется. Чтобы OnKeyDown фомы могло вызваться вставь в цикл вызов Application.ProcessMessages. Эта функция будет выполнять обработку накопившихся системных сообщений. В OnKeyDown ставишь флажок; после Application.ProcessMessages проверяешь его.
| Цитата: | | Еще пробовал вынести цикл в отдельный поток, проблема с Ctrl+C решается, но там не работает вызов хранимой процедуры |
Потоки – вещь хорошая. Но есть нюансы с обращением к визуальным элементам из потока. Если таковые есть, их нужно оформлять процедурой и вызывать через Synchronize. Может в этом причина ошибки? Вообще-то компонент невизуальный, но мало ли... Что такое fmQuery в сообщении об ошибке? Случайно не форма? _________________ Ответ готов, готов ли твой вопрос? |
|
| В начало |
|
 |
 KVas
Новичок

Возраст: 46
Знак зодиака: 
Зарегистрирован: 26.08.2008
Сообщения: 17
|
|
|
Цитата |
|
| Шурик писал(а): |
| delphi: | function KeyPressed( VK_Value: Integer ): Boolean; begin Result := GetKeyState( VK_Value ) < 0 ; end;
| |
KeyPressed почему-то не сработало, а вот Application.ProcessMessages самое то и есть, очень большое спасибо за оперативный компетентный ответ.
| Цитата: | | Что такое fmQuery в сообщении об ошибке? Случайно не форма? |
Да - fmProc это отдельная форма, на которой расположены общие процедуры и FIB компоненты доступа к БД, в том числе и Query (клас TpFIBQuery).
Еще раз большое спасибо, уже не первый раз меня выручаете. |
|
| В начало |
|
 |
 Шурик
Я живу тут....

Возраст: 42
Знак зодиака: 
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
|
|
|
Цитата |
|
| Цитата: | | KeyPressed почему-то не сработало |
А что именно?
Просто интересно... Это рабочая процедура, которую я сам использую.
| Цитата: | | Да - fmProc это отдельная форма |
Возможно в этом причина. Смешивать формы с потоками нужно осторожно.
Добавлено спустя 5 минут 39 секунд:
Использование Application.ProcessMessages имеет ещё один эффект, обычно полезный. Если по нажатию на кнопку, меню и т.п. ты выполняешь процедуру, занимающую много времени, пользовательский интерфейс "замерзает" – не реагирует ни на что. Дело в том, что визуальный интерфейс "живёт" за счёт обработки событий, которые система шлёт приложению - движения мыши, нажатия. Но они в пределах приложения выполняются последовательно, не прерывая друг друга. Выполняя Application.ProcessMessages в "длинной" процедуре ты инициируешь обработку накопившихся сообщений и это "оживляет" интерфейс. _________________ Ответ готов, готов ли твой вопрос? |
|
| В начало |
|
 |
Hunter
Энтузиаст

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

Возраст: 42
Знак зодиака: 
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
|
|
|
Цитата |
|
| Цитата: | | если часто вызывать ProcessMessages() в "коротких" циклах, то это создает излишнюю нагрузку на процессор |
Ну да. Я обычно пишу что-то типа такого:
| delphi: | for i:=1 to SomeCount do begin ... if (i mod 1000) = 0 then Application.ProcessMessages; ... end;
|
Через сколько итераций цикла вызывать ProcessMessages – зависит от логики конкретного цикла. Где-то это 100, где-то 1000 или 10000. _________________ Ответ готов, готов ли твой вопрос? |
|
| В начало |
|
 |
 KVas
Новичок

Возраст: 46
Знак зодиака: 
Зарегистрирован: 26.08.2008
Сообщения: 17
|
|
|
Цитата |
|
Извините не сразу ответил, думал тема закрыта
| Шурик писал(а): |
А что именно?
Просто интересно... Это рабочая процедура, которую я сам использую.
|
Функцию разместил в разделе описания переменных той же процедуры, где цикл, для удобства отладки код записал в таком виде.
| delphi: | k_p1:=KeyPressed( VK_Control ); k_p2:=KeyPressed( Ord('C') ); if k_p1 and k_p2 then Break;
|
и k_p1, и k_p2 возвращают False независимо от того, нажимал я Ctrl+C или нет. Может функцию в каком другом месте нужно описать?
| Цитата: | | Выполняя Application.ProcessMessages в "длинной" процедуре ты инициируешь обработку накопившихся сообщений и это "оживляет" интерфейс. |
О-очень приятный "побочный" эффект. Решал эту проблему через sleep(100), но не всегда нормально работало. |
|
| В начало |
|
 |
|
|
 |
 Шурик
Я живу тут....

Возраст: 42
Знак зодиака: 
Зарегистрирован: 15.01.2003
Сообщения: 1951
Откуда: Киев
|
|
|
Цитата |
|
| Цитата: | | k_p1, и k_p2 возвращают False независимо от того, нажимал я Ctrl+C или нет |
"Нажимал"... Функция KeyPressed проверяет нажата ли клавиша в данный момент. Скорее всего у тебя интервал между проверками достаточно большой; нажатие клавиши происходит между проверками; выходит, что в момент проверки ничего не нажато. Если ты попробуешь, подержишь Ctrl+C нажатыми подольше, думаю KeyPressed их "заметит".
С этой точки зрения для тебя более предпочтителен вариант с событиями и Application.ProcessMessages. События генерируются по каждому нажатию кнопки и ждут в очереди, когда их обработают. Т.е. как редко бы ты не проверял после нажатия кнопки по ProcessMessages ты получишь её из очереди событий.
| Цитата: | | Может функцию в каком другом месте нужно описать? |
Если компилятор её видит – разместил правильно  _________________ Ответ готов, готов ли твой вопрос? |
|
| В начало |
|
 |
|