2011-01-18 32 views
14

Tengo una aplicación Swing con un modelo y una vista. En la vista (GUI) hay muchos componentes, cada uno de los cuales se correlaciona con alguna propiedad de un objeto modelo y muestra su valor.Cómo deshabilitar temporalmente los detectores de eventos en Swing?

Ahora hay algunos componentes de la interfaz de usuario que activan automáticamente la actualización de algunas propiedades del modelo cuando su valor cambia en la interfaz de usuario. Esto requiere que vuelva a cargar el modelo completo en la interfaz de usuario. De esta manera estoy ingresando un ciclo de actualización infinito, ya que cada recarga de modelo en la UI dispara otra recarga del modelo.

Tengo un indicador que indica el proceso de carga, que me gustaría utilizar para suprimir temporalmente las notificaciones del oyente, mientras que los campos de IU se establecen desde el modelo. Entonces mi pregunta es:

¿Hay alguna manera de desactivar globalmente temporalmente los oyentes de algunos componentes en Swing sin quitarlos ni volverlos a unir?

+2

Ver también http://stackoverflow.com/questions/4716072 – trashgod

+0

Gracias por el enlace! Parece un problema similar y no hay una solución satisfactoria para él. – MicSim

Respuesta

7

Se puede usar una clase base común para sus oyentes y en ella, tienen un método estático para convertir los oyentes o desactivar:

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); 
     } 
    } 
} 

Sus oyentes tendrían que aplicar doPerformAction() en lugar de actionPerformed().

(esto sería horrible en un escenario de la empresa, pero en una sola máquina virtual como modelo de oscilación, que debería funcionar bien)

4

Normalmente yo uso una bandera que indica cambios en la API o los cambios del usuario. Para cada uno de los oyentes, verificaría la bandera y si se trata de cambios en la API, simplemente regrese.

2

This question parece un problema similar y ninguna solución satisfactoria a ella .

Encontré este article útil para examinar críticamente mis propios diseños.

¿Hay alguna manera de desactivar globalmente temporalmente los oyentes de algunos componentes en Swing sin quitarlos ni volverlos a unir?

Cada JComponent mantiene un , que es accesible para su subclase. Si es necesario, siempre puede operar en la lista directamente o crear el comportamiento deseado en su implementación personalizada de EventListener

4

Mientras buscaba stackoverflow, encontré esta pregunta. Pensé en agregar mi opinión/respuesta.

Realmente es una mala idea para temporalmente desactivar oyentes de eventos en Swing. Si su código no funciona (o si algo falla), es posible que no pueda volver a dar vida a su aplicación; responda al usuario y a otros eventos.

Si desea descartar (responder pero no hacer nada) los eventos del usuario, puede usar un panel de vidrio que simplemente puede ignorar los eventos.

Si su EDT está ocupado (que nuevamente debe evitar tanto como sea posible) y deseaba descartar la acción del usuario para ese período, aún puede usar un cristal y eliminarlo utilizando invokeLater para eliminar el panel después de todos los eventos han sido respondidos (ignorado por el cristal) a.

Se pueden encontrar detalles completos que incluyen un SSCE en esta pregunta.

java wait cursor display problem

3

Como se mencionó anteriormente, la GlassPane es útil en este sentido. Aquí está un ejemplo sencillo:

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()); 
    } 
} 

}

Cuestiones relacionadas