MouseWheel Flicker, más sobre el por qué

Hace unos días publiqué una pregunta sobre un programa que provocaba que el texto de la pantalla cambiara de color cuando se desplazaba la rueda del ratón. Desafortunadamente, fue una pregunta mal formulada con demasiado código publicado para ser particularmente útil.

Recibí varias respuestas, una de las cuales fue del usuario trashdog que publicó algo que solucionó el problema (que se puede encontrar en la parte inferior de esta página aquí: La ventana se queda en blanco durante el evento MouseWheelMotion), sin embargo, después de leer las descripciones de clase de todas las cosas que no sabía en el programa que publicó y pasar por su ejecución, no entiendo por qué logra un efecto diferente al mío.

El suyo parece registrar cada movimiento de la rueda del mouse mientras que el mío solo hace el movimiento inicial. También varias personas comentaron que probablemente no pudieron replicar el efecto de mi programa porque era muy grande.

A continuación se muestra una versión extremadamente simplificada que aún provoca el mismo efecto (espero).

Pregunta: ¿Qué es fundamental ¿Cuál es la diferencia entre los dos programas que corrige que la pantalla se quede en blanco cuando se procesan los eventos de la rueda del mouse?

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.LinkedList;
import javax.swing.JFrame;

public class WheelPrinter implements MouseWheelListener, Runnable {

    JFrame frame;
    LinkedList colorList;
    int colorCount;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        WheelPrinter w = new WheelPrinter();
        w.run();
    }

    public WheelPrinter() {
        frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.addMouseWheelListener(this);
        frame.setVisible(true);
        frame.setBackground(Color.WHITE);
        colorList = new LinkedList();
        colorList.add(Color.BLACK);
        colorList.add(Color.BLUE);
        colorList.add(Color.YELLOW);
        colorList.add(Color.GREEN);
        colorList.add(Color.PINK);
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        colorChange();
    }

    @Override
    public void run() {
        while(true) {
            draw(frame.getGraphics());
            try {
                Thread.sleep(20);
            } catch (Exception ex) {

            }
        }
    }

    public void draw(Graphics g) {
        g.setColor(frame.getBackground());
        g.fillRect(0,0,frame.getWidth(),frame.getHeight());
        g.setFont(new Font("sansserif", Font.BOLD, 32));
        g.setColor(frame.getForeground());
        g.drawString("yes", 50, 50);
    }

    public void colorChange() {
                colorCount++;
        if (colorCount > 4) {
            colorCount = 0;
        }


        frame.setForeground((Color) colorList.get(colorCount));
    }

    }

(Intente girar la rueda del mouse muy fuerte si intenta ejecutar mi código y se volverá aún más obvio)

preguntado el 12 de junio de 12 a las 19:06

2 Respuestas

  1. while(true) { es bucle sin fin, sin interrupción; fe

  2. utilizado Swing Timer en lugar de Runnable#Thread retrasado por Thread.Sleep()

  3. pintar a la JPanel or JComponent, no directamente a la JFrame

  4. toda la pintura al Swing JComponent debe hacerse en paintComponent()

  5. más en el Tutorial de gráficos 2D

editar

enter image description here

enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.util.LinkedList;
import java.util.Queue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 * based on example by @trashgod
 * 
 * @see http://stackoverflow.com/a/10970892/230513
 */
public class ColorWheel extends JPanel {

    private static final int N = 32;
    private static final long serialVersionUID = 1L;
    private final Queue<Color> clut = new LinkedList<Color>();
    private final JLabel label = new JLabel();

    public ColorWheel() {
        for (int i = 0; i < N; i++) {
            clut.add(Color.getHSBColor((float) i / N, 1, 1));
        }
        //clut.add(Color.BLACK);
        //clut.add(Color.BLUE);
        //clut.add(Color.YELLOW);
        //clut.add(Color.GREEN);
        //clut.add(Color.PINK);
        label.setFont(label.getFont().deriveFont(36f));
        label.setForeground(clut.peek());
        label.setText("@see http://stackoverflow.com/a/10970892/230513");
        setBackground(Color.white);
        add(label);
        label.addMouseWheelListener(new MouseAdapter() {

            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                label.setForeground(clut.peek());
                clut.add(clut.remove());
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        int w = SwingUtilities.computeStringWidth(label.getFontMetrics(
                label.getFont()), label.getText());
        return new Dimension(w + 20, 80);
    }

    private void display() {
        JFrame f = new JFrame("ColorWheel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ColorWheel().display();
            }
        });
    }
}

Respondido el 12 de junio de 12 a las 22:06

¡Muchas gracias! ¿Qué significa fe? ¿Y el programa no permanecerá abierto y escuchando si no hay un ciclo while que lo mantenga funcionando y dibujando? - John Smith

aaaach, realmente no puedo ver la razón para molestarme con los gráficos, especialmente en el caso de que vinculaste un gran ejemplo de @trashgod, algunos cambios más que menores, no importantes para la salud en este mundo, mira mi edición aquí - mKorbel

La fundamental la diferencia es que está tratando de interactuar con el objeto Graphics desde el hilo incorrecto y sin saber nada sobre el estado en el que se encuentra el objeto Graphics en ese momento.

La forma generalmente correcta de interactuar con un objeto Graphics en Swing es creando un componente personalizado que anule el paintComponent(Graphics) método. Haces tu dibujo mientras estás dentro de ese método.

Su método colorChange() puede decirle a su componente que se vuelva a dibujar llamando repaint(), que eventualmente conducirá a una llamada a paintComponent(Graphics) en el hilo correcto en el momento correcto.

Ver tutorial aquí

Respondido el 13 de junio de 12 a las 01:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.