2011-01-18 2 views
14

У меня есть приложение Swing с моделью и видом. В представлении (GUI) есть много компонентов, каждый из которых сопоставляет некоторое свойство модельного объекта и отображает его значение.Как временно отключить прослушиватели событий в Swing?

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

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

Есть ли способ глобально временно отключить прослушиватели некоторых компонентов в Swing без их удаления и повторного подключения?

+2

Смотрите также http://stackoverflow.com/questions/4716072 – trashgod

+0

Спасибо за ссылку! Похож на аналогичную проблему и нет удовлетворительного решения. – MicSim

ответ

7

Вы могли бы использовать общий базовый класс для слушателей и в нем есть статический метод для включения слушателей или выключать:

public abstract class BaseMouseListener implements ActionListener{ 

    private static boolean active = true; 
    public static void setActive(boolean active){ 
     BaseMouseListener.active = active; 
    } 

    protected abstract void doPerformAction(ActionEvent e); 

    @Override 
    public final void actionPerformed(ActionEvent e){ 
     if(active){ 
      doPerformAction(e); 
     } 
    } 
} 

Ваши слушатели должны реализовать doPerformAction() вместо actionPerformed().

(Это было бы ужасно в сценарии предприятия, но в одном-VM модели, как в свинг, он должен работать нормально)

4

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

2

This question выглядит подобной проблемой и не удовлетворительного решения к нему ,

Я нашел это article полезным при критическом рассмотрении моих собственных проектов.

Есть ли способ глобально временно отключить прослушиватели некоторых компонентов в Swing без их удаления и повторного подключения?

Каждый JComponent поддерживает EventListenerList, доступный вашему подклассу. При необходимости вы всегда можете напрямую работать с списком или создавать желаемое поведение в своей пользовательской реализации: EventListener

4

При поиске stackoverflow я нашел этот вопрос. Я подумал добавить свое мнение/ответ.

Это действительно плохой идеей, чтобы временно отключить прослушиватели событий в Swing. Если ваш код сломан (или что-то еще не так), вы не сможете вернуть приложение к жизни - отвечать на пользовательские и другие события.

Если вы хотите отменить (ответить, но ничего не делать) на пользовательские события, вы можете использовать стеклянную панель, которая может просто игнорировать события.

Если ваш EDT занят (что еще раз нужно избегать как можно больше), и вы хотели отказаться от действия пользователя за этот период, вы все равно можете использовать стеклянную панель и удалить ее с помощью invokeLater, чтобы удалить панель после всех событий были откликаются (игнорируются стеклянным стеклом).

Полная информация, включая SSCE, может быть найдена в этом вопросе.

java wait cursor display problem

3

Как уже упоминалось выше, GlassPane полезен в этом отношении. Вот простой пример:

import javax.swing.JFrame; 
import javax.swing.JButton; 
import javax.swing.SwingWorker; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 
import java.awt.Color; 
import java.awt.Cursor; 
import java.awt.Graphics; 
import java.awt.FlowLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 


public class GlassPaneExample extends JFrame implements ActionListener { 

private JButton btnDisable; 
private JButton btnTestOne; 
private JButton btnTestTwo; 
private MyGlassPane glass; 
private boolean actionAllowed = true; 

public GlassPaneExample() { 

    // init JFrame graphics 
    setBounds(300, 300, 300, 110); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setLayout(new FlowLayout()); 
    setVisible(true); 

    // init buttons 
    btnTestOne = new JButton("Button one"); 
    add(btnTestOne); 
    btnTestTwo = new JButton("Button two"); 
    add(btnTestTwo); 
    btnDisable = new JButton("Disable ActionListeners for 2 seconds"); 
    add(btnDisable); 

    // create Glass pane 
    glass = new MyGlassPane(); 
    setGlassPane(glass); 

    // add listeners 
    btnTestOne.addActionListener(this); 
    btnTestTwo.addActionListener(this); 
    btnDisable.addActionListener(this); 

} 

public static void main(String[] args) { 
    new GlassPaneExample(); 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    JButton src = (JButton)e.getSource(); 
    if (src.equals(btnDisable)) { 

     // setting glasspane visibility to 'true' allows it to receive mouse events 
     glass.setVisible(true); 
     setCursor(new Cursor(Cursor.WAIT_CURSOR)); 

     SwingWorker sw = new SwingWorker() { 

      @Override 
      protected Object doInBackground() 
        throws Exception { 
       Thread.sleep(2000); 
       return null; 
      } 

      @Override 
      public void done() { 
       // set cursor and GlassPane back to default state 
       setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 
       glass.setVisible(false); 
       // allow actions to be received again 
       actionAllowed = true; 
      } 
     }; 
     sw.execute(); 

    } else if (actionAllowed) { 
     if (src.equals(btnTestOne)) { 
      JOptionPane.showMessageDialog(this, "BUTTON ONE PRESSED"); 
     } else if (src.equals(btnTestTwo)) { 
      JOptionPane.showMessageDialog(this, "BUTTON TWO PRESSED"); 
     } 
    } 
} 

class MyGlassPane extends JPanel { 

    public MyGlassPane() { 

     setOpaque(false); 

     addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       actionAllowed = false; 
      } 
     }); 
    } 

    //Draw an cross to indicate glasspane visibility 
    public void paintComponent(Graphics g) { 
     g.setColor(Color.red); 
     g.drawLine(0, 0, getWidth(), getHeight()); 
     g.drawLine(getWidth(), 0, 0, getHeight()); 
    } 
} 

}

Смежные вопросы