4

I've written this simple program which displays key presses, draws the phrase "Hello World," where one's cursor moves (with a trail mode when clicked) and also cycles through the Colors in which "Hello World," is picked out when the mouse wheel is scrolled. However there is a problem with this: When the mouse wheel scrolls the entire window goes blank (showing the default grey color from when you first make a component visible) and will then be redrawn with the color change (a very small change only to the "Hello World," which doesn't seem to require that the whole frame be redrawn.

The time for which the blankness occurs seems to correlate with the force with which the mouse wheel is scrolled, if I scroll very lightly there is only a very tiny moment where everything is not displayed, however scrolling very hard can make the window go blank for 2-3 seconds.

I've tried double buffering - thinking that this might be some sort of screen flicker - but it has made no change and I'm at a loss as to what could be causing this weird effect. It's as if the frame image is loading while the Wheel motion event is happening. (Is there perhaps a way to exit from the wheel event immediately so as to reduce loading time? (This is just my guesses as to possible solutions)).

The code is below. Any ideas would be greatly appreciated.

package keymouse;

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.BufferStrategy;
    import java.util.LinkedList;
    import javax.swing.JFrame;

    public class KeyMouse implements KeyListener,
            MouseMotionListener, MouseListener, MouseWheelListener, Runnable {

        boolean trailMode = false;
        boolean exists = false;
        display window;
        LinkedList wordList;
        LinkedList trailList;
        LinkedList colorList;
        Point mousePoint;
        int TRAIL_SIZE = 10;
        boolean init = true;
        int FONT_SIZE = 32;
        int mouseY;
        int mouseX;
        int y;
        int colorCount = 0;

        public static void main(String[] args) {
            KeyMouse k = new KeyMouse();
            k.run();
        }

        public KeyMouse() {
            window = new display();
            window.addKeyListener(this);
            window.addMouseMotionListener(this);
            window.addMouseListener(this);
            window.addMouseWheelListener(this);
            window.setBackground(Color.WHITE);
            window.setForeground(Color.BLACK);
            wordList = new LinkedList();
            trailList = new LinkedList();
            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 keyTyped(KeyEvent e) {
            // do nothing
        }

        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode;
            if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                stop();
            }

            keyCode = e.getKeyCode();
            addMessage("Pressed:" + e.getKeyText(keyCode));
        }

        @Override
        public void keyReleased(KeyEvent e) {
            //do nothing
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            Point p = new Point(e.getX(), e.getY());
            addLocation(p);
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            Point p = new Point(e.getX(), e.getY());
            addLocation(p);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
        }

        @Override
        public void mousePressed(MouseEvent e) {
            trailMode = true;

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            trailMode = false;
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            //do nothing
        }

        @Override
        public void mouseExited(MouseEvent e) {
            //do nothing
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {


            System.out.println(e.getWheelRotation());
            colorCount++;
            if (colorCount > 4) {
                colorCount = 0;
            }


            window.setForeground((Color) colorList.get(colorCount));

        }

        @Override
        public void run() {
            window.createBufferStrategy(2);
            BufferStrategy strategy = window.getBufferStrategy();

            while (true) {
                draw(strategy.getDrawGraphics());
                strategy.show();
                try {
                    Thread.sleep(20);
                } catch (Exception ex) {
                }
            }
        }

        public void draw(Graphics g) {
            //draw background

            g.setColor(window.getBackground());
            g.fillRect(0, 0, window.getWidth(), window.getHeight());

            //draw Text
            g.setColor(window.getForeground());
            g.setFont(new Font("sansserif", Font.BOLD, 32));

            int count = trailList.size();
            if (trailList.size() > 1 && trailMode == false) {
                count = 1;
            }

            if (exists == true) {
                for (int i = 0; i < count; i++) {
                    Point p = (Point) trailList.get(i);
                    g.drawString("Hello World", p.x, p.y);
                }
            }

            g.setColor(Color.BLACK);
            y = 56;
            for (int i = 0; i < wordList.size(); i++) {
                String word = (String) wordList.get(i);
                g.drawString((String) wordList.get(i), 100, y);
                y += 32;
            }


        }

        public void addMessage(String message) {
            if (y >= window.getHeight()) {
                wordList.remove(0);
            }
            wordList.add(message);
        }

        public void addLocation(Point h) {
            exists = true;
            trailList.addFirst(h);
            if (trailList.size() > TRAIL_SIZE) {
                trailList.removeLast();

            }
        }

        public void printMessages() {
            for (int i = 0; i < wordList.size(); i++) {
                System.out.println(wordList.get(i));
            }
        }

        private void stop() {
            System.exit(0);
        }
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
John Smith
  • 231
  • 3
  • 12
  • 1
    `while (true) { .. Thread.sleep(20);` Use a Swing `Timer` instead. – Andrew Thompson Jun 10 '12 at 08:19
  • 1
    For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jun 10 '12 at 08:21
  • 1
    You implement `Runnable`, did you intend to run the the `run()` method in a background thread? That's not the case, you're calling it directly. – Christoph Walesch Jun 10 '12 at 08:26
  • @AndrewThompson So the reason that the moment of blank screen is happening is because the render loop refreshes are not synced with it properly? How best would Swing Timer be used here? (I can't see how it could be synced with an MWListener as that is a user input. I'm quite new to java and programming in general. Sorry for asking you to elaborate. – John Smith Jun 10 '12 at 09:39
  • @noise Should I not be calling the run method directly? I thought I had to call it for the render loop to actually start and continually draw the different events. Am I mistaken? I'm quite new to java and programming in general. Sorry for asking you to elaborate. – John Smith Jun 10 '12 at 09:40
  • *"So the reason that.."* I might have more information for you once I see the SSCCE. – Andrew Thompson Jun 10 '12 at 10:03
  • @JohnSmith calling `run()` does noting but calling this method directly in the current thread. If you want a background thread, you must create a `java.lang.Thread`. Fortunately, you don't need to do that directly. Take Andrew's advice and use a `javax.swing.Timer`. – Christoph Walesch Jun 10 '12 at 10:13

1 Answers1

3

Absent a complete example, I can't reproduce the effect you describe. You might compare your code to this example, which exhibits no apparent blanking.

In general,

  • JPanel is double buffered by default; it's unusual to need a different buffer strategy.
  • AnimationTest illustrates a Swing Timer and how to display your average paint period.
  • MouseAdapter is convenient for overriding a small number of methods.
  • When possible, use generic parameters for type safety.

ColorWheel image

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;

/**
* @see https://stackoverflow.com/a/10970892/230513
*/
public class ColorWheel extends JPanel {

    private static final int N = 32;
    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));
        }
        this.setBackground(clut.peek());
        label.setText(getBackground().toString());
        this.add(label);
        this.addMouseWheelListener(new MouseAdapter() {

            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                setBackground(clut.peek());
                label.setText(getBackground().toString());
                clut.add(clut.remove());
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(320, 240);
    }

    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();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045