2012-01-24 2 views
3

У меня есть MouseListener тема, где этот метод вызывается каждый раз, когда есть щелчок:делают эффективного внедрение этого Java MouseListener Logic

public void mousePressed(MouseEvent event){ 

    //my Logic here 

} 

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

Но то, что происходит, когда логика обрабатывается, входящие клики поставлены в очередь, и даже когда клик остановлен, qued клики продолжают называть этот метод mousePressed, в результате у меня есть несколько отложенных исполнений.

К сожалению, у меня нет контроля над слушателем (почему он задает вопросы и продолжает отправлять задержанные клики), поэтому в таком сценарии вы можете рассказать мне, что является эффективным способом обработки, так что я не делаю очереди для задержки в моей обработке.

Я думаю, что самый очевидный способ - использовать другой поток, но мне интересно, что это может вызвать столько потоков за меньшее время, или есть ли способ заблокировать только один поток, в то время как остальные клики просто пройдут через пустые цикл?

+1

Возможно, вы захотите подражать тому, как Swing обрабатывает запросы на перерисовку - он игнорирует запросы, когда они складываются. Пожалуйста, посмотрите здесь более подробно: [Живопись в AWT и Swing] (http://java.sun.com/products/jfc/tsc/articles/painting/). И да, я думаю, что независимо от того, вы захотите использовать фоновый поток, возможно, пул потоков. –

+0

@HovercraftFullOfEels, это метод JNI, где фактический прослушиватель мыши находится из собственного кода, в котором нет Swing. – Johnydep

+0

Хорошо, если я просто начинаю новый поток, а затем вызываю метод, по крайней мере, я не пропущу ни одного щелчка, хотя все же результаты задерживаются и во многих параллельных потоках я предполагаю, что использование какого-то летучего булевского флага может быть ответом, полагаю, что так. – Johnydep

ответ

1

Одним из решений было бы получить доступ к компоненту, на который пользователь нажал и отключил его во время обработки MouseListener. Таким образом, он не принимает новые клики. Это будет иметь дополнительное преимущество, чтобы дать пользователю визуальную обратную связь, что он не должен нажимать на компонент в это время.

Вы можете получить доступ к компоненте через MouseEvent:

public void mousePressed(MouseEvent event) { 
    event.getComponent().setEnabled(false); 
    try { 

    // .... 

    } finally { 
    event.getComponent().setEnabled(true); 
} 

В общем, хотя вы не должны делать слишком много вычислений в свинге событиях слушающего потока, потому что свинг также нуждается в ней для обработки других событий и живописи. Вы должны использовать отдельные потоки для выполнения фактической работы и просто запускать их в MouseListener. Вы также можете использовать ExecutorService для упрощения этого. Было бы неплохо отключить компонент gui во время всего вычисления, чтобы дать пользователю обратную связь.

Edit: Это решение, конечно, зависит от Swing. Любое подобное решение зависит от деталей вашей библиотеки графического интерфейса, поэтому, если вы используете свою собственную графическую библиотеку, вы являетесь своей собственной.

Вы можете, конечно, использовать общее решение, включающее отдельные потоки для выполнения работы. Я действительно рекомендую здесь ExecutorService, вам не нужно заботиться о деталях и просто отправлять задания для выполнения. Затем вы можете иметь простую изменчивую логическую переменную, которая указывает, выполняется ли действие в настоящее время, а новые клики должны игнорироваться.

+0

спасибо, что я не могу получить доступ к компоненту, так как это может быть что-то вроде chrome, windows media player и т. Д., Я просто подключаюсь к системной DLL для получения кликов. И в моей реализации все CLI основано без какого-либо Swing GUI, созданного в данный момент, в основном в моей логике я использую JNA для получения активного заголовка окна, сравниваю его с предыдущими значениями и затем игнорирую, если он одинаковый (для нескольких кликов по одному компоненту), иначе вызовите другой метод, если активный компонент отличается. – Johnydep

+0

Подождите, вы вообще не используете Swing? Вы должны сказать это в вопросе. Он имеет тег «swing» и упоминает имена хорошо известных классов Swing, поэтому я предположил, что Swing - это тот, который вызывает ваш код. Если вы не используете Swing, вы, вероятно, не должны использовать классы Swing, так как это может быть очень запутанным для будущих читателей вашего кода. –

+0

Итак, теперь я реализовал его с помощью простого if (boolean) {new Thread(). Start()}, где в потоке я устанавливаю логическое значение false и после его завершения верну его в true – Johnydep

2

Обновления: См. Комментарии Филлипа относительно того, почему это не работает для Swing!

К сожалению, у вас нет доступа к eventListener. Идеальным решением было бы отменить регистрацию обратного вызова во время его выполнения.

Вот решение , который эмулирует регистрацией функции обратного вызова в то время как она выполняется, если вы хотите, поставленные в очередь щелкает уйти:

private AtomicBoolean engaged = new AtomicBoolean(); // thread-safe boolean 

public void mousePressed(MouseEvent event){ 
    if (!engaged.get()) { 
     engaged.set(true); 

     // your logic here 

     engaged.set(false); 
    } 
} 

В AtomicBoolean действует как тест-и-набор замка предотвращая одновременное выполнение несколькими потоками обратного вызова нажатого события. Очередь прессы будут рассеиваться во время блокировки.

+0

Я протестировал его, но он, похоже, не повлиял на результат, может быть, я что-то пропустил, но я попробую снова утром, сейчас 3:30, спасибо – Johnydep

+0

Это не имеет никакого эффекта, потому что Swing не является мульти- резьба. Все события выполняются последовательно в одном потоке, поэтому, когда вызывается метод mousePressed, предыдущие вызовы всегда уже завершены. –

+0

И вообще было бы очень важно поместить вызов 'involved.set (false)' в блок finally. В противном случае любое исключение или раннее возвращение будут постоянно отключать компонент. –