TAction и горячие клавиши
например
и если удерживать нажатой клавишу F11 (в данном примере)
то обработчик события будет запускаться N-ное количество раз.
Понять могу, код нажатой клавиши из очереди буфера клавиатуры активирует действие и т.д. Но, ведь такое поведение не всегда необходимо и допустимо (с точки зрения программы)!
Контролировать запуск какого-либо метада по событию
OnKeyDown не всегда удобно.
Есть ли красивое решение задачи:
По нажатии и удержании клавиши TAction->Execute() выполняется
один раз.
На нажатие:
if(!bool)
{
actRecordImageShow->ShortCut = 122;
bool=true;
}
На отпускание
bool=false;
Контролировать запуск какого-либо метада по событию
OnKeyDown не всегда удобно.
Объекты TAction должны "жить" сами по себе. У меня впроекте
некоторые объекты окна связаны с индивидуальными обработчиками
OnKeyDown и OnKeyUp. Помнить о том, чтобы в них ( а также создавать
для других объектов ) описывать для всех TAction такую конструкцию, это не очень хорошая идея. ;)
Я пробовал вариант такой:
В обработчике TAction использовать отсечку лишних запусков
if ( ImageShowRun ) return;
ImageShowRun = true;
try
{
... что-то делаем ...
}
catch(...){}
ImageShowRun = false;
}
Но, к сожалению, это не помогает!
У меня задача - по нажатию клавиши F11 отобразить окно с изображением (берётся из ftBlob поля записи). Повторное нажатие
этой же клавиши (что, Я думаю, удобно) должно закрыть окно просмотра.
Ниже приведенный пример не помогает.
После того как "отсечка" по истинному значению ImageShowRun помогла
исключить повторные запуски, выполнение обработчика TAction
завершилось, ImageShowRun принял значение ЛОЖЬ и следующий
запуск TAction (по причине удержания клавиши F11) запустил заново
обработчик TAction, который, по совему принципу работы, закрыл окно
просмотра! Вот и получается, что Я вижу "мелькающее окно".
А что должно быть? По-моему, утопление F11 к этому и должно привести. Упал-отжался - открыл-закрыл.
Пусть Action вызывает только Show и Hide, а окно просмотра в обработчике OnShow реализует остальную логику.
кто "давно не пользовался билдером" ;(
Уважаемые участники форума, пожалуйста,
давайте дельные советы, а не высказывайте мнения,
типа "спасение утопающих, дело рук самих утопающих".
Наводящий вопрос на тему:
возможно поможет в конце обработчика события TAction
очищать буфер клавиатуры. Как это сделать?
на KeyDown показал, на KeyUp скрыл, окно на OnShow показало картинку.... чего сложного... даже не понимаю.
имхо, оптимально. без всяких очисток буфера клавиатуры...
[quote="nikipelovav"]
Объекты TAction должны "жить" сами по себе. У меня впроекте
некоторые объекты окна связаны с индивидуальными обработчиками
OnKeyDown и OnKeyUp. Помнить о том, чтобы в них ( а также создавать
для других объектов ) описывать для всех TAction такую конструкцию, это не очень хорошая идея.
[/quote]
ничего они никому не должны, а написать несколько лишних (которые и не будут лишними) строчек кода... если это проблема, то извините :)
PS: и как раз "тот кто давно не пользовался билдером" тоже говорит правильно.
"Пусть Action вызывает только Show и Hide, а окно просмотра в обработчике OnShow реализует остальную логику."
И что же здесь правильного, если переполненый кодом нажатой клавиши
буфер клавиатуры будет вызывать и вызывать обработчик TAction.
И на основании чего "Пусть Action вызывает только Show и Hide".
Если на основании свойства Окно->Visible, то это тоже, что и
"... реализует остальную логику".
Я понимаю, что описать OnKeyDown и OnKeyUp даст желаемый результат.
Я это ранее уже делал с другим окном.
Вопрос в том, что многие "действия" в программе описаны через TAction.
И, чаще, необходимо избежать повторения запуска. И нужно найти красивое решение этой проблемы, потребующее минимум кода.
Я воспользовался поиском на форуме, оказалось такой вопрос уже задавали. Предложенным решением было использование таймера.
Логическую переменную, которая разрешала выполнение тела обработчика TAction контролировал Таймер. Как Я понимаю, он ждал
0,3 - 1,0 секунды после завершения работы обработчика TAction
и лишь тогда изменял значение логической переменной. При этом
предполагается , что за время 0,3 - 1,0 сек. опусташится буфер клавиатуры.
Но неужели это единственный способ. А если в программе 50 TAction,
что, делать 50 таймеров?
Можно ещё VCL переписать, чтобы TAction по-человечески был, а не сбоку припёка.
что, делать 50 таймеров?
Можно шарить единственный.
Во первых, надо признаться, Я сам себя немного запутал!
Но мне никто не заметил, что что-то не так!
Вот что Я писал:
У меня задача - по нажатию клавиши F11 отобразить окно с изображением (берётся из ftBlob поля записи). Повторное нажатие
этой же клавиши (что, Я думаю, удобно) должно закрыть окно просмотра.
... Вот и получается, что Я вижу "мелькающее окно".
TAction на главной форме получает информацию о нажатой клавише и генерирует OnExecute. Но как только обработчик OnExecute отображает другое окно, сообщения о нажатой клавише поступают в это окно, а TAction умолкает!!!
Почемуже при удержаной горячей клавише у меня окно закрывалось?
Ответ прост. Вы мне советовали использовать обработчики OnKeyDown и OnKeyUp. А Я Вам писал, что уже использовал их в подобных целях!
Просто забыл!!!! ;))) В обработчике OnKeyDown Я закрывал форму.
Вот и получалось "что Я вижу 'мелькающее окно'".
Вернёмся теперь к повторному запуске OnExecute.
Действительно помогает отсечка повторных запусков логической переменной. Но, чтобы не погрязнуть в огромном количестве однотипных структур обработчиков OnExecute:
IsRun = true;
try
{
// делаем что-либо
}
catch(...){}
IsRun = false;
Я для себя решил. Создам класс, порождённый от TAction и буду
все обработчики событий присваивать собственному указателю,
который будет вызываться в выше описанной структуре кода
из стандартного обработчика OnExecute.
Вот пример кода:
{
public:
__fastcall BAction(Classes::TComponent* Owner);
// пользовательский обработчик OnExecute
TNotifyEvent OnExecuteB;
protected:
// собственный обработчик OnExecute
void __fastcall BActionExecute ( TObject *Sender );
// признак выполнения метода
bool OnExecuteRun;
};
__fastcall BAction::BAction(Classes::TComponent* Owner): TAction(Owner)
{
OnExecute = BActionExecute;
OnExecuteRun = false;
}
void __fastcall BAction::BActionExecute ( TObject *Sender )
{
if ( OnExecuteRun ) return; // выход, если сейчас выполняется
OnExecuteRun = true;
try { OnExecuteB( Sender ); } catch(...){} // пользовательский метод
OnExecuteRun = false;
}
Поздравляю с решением проблемы :) Удачи!