鼠标滚轮移动期间窗口变空白

4
我编写了这个简单的程序,它可以显示键盘按键,绘制短语“Hello World”,并在鼠标滚轮滚动时循环切换“Hello World”所选颜色。然而,存在一个问题:当鼠标滚轮滚动时,整个窗口都会变成空白(显示的是首次使组件可见时的默认灰色),然后再以新颜色重新绘制(仅对“Hello World”进行微小更改,似乎不需要重新绘制整个框架)。
空白发生的时间似乎与滚动鼠标轮的力度有关,如果我轻轻地滚动,几乎没有任何东西未被显示出来,但是强烈滚动可能会使窗口变空白2-3秒钟。
我尝试了双缓冲,认为这可能是某种屏幕闪烁,但没有任何改变,我不知道是什么原因导致了这种奇怪的效果。就像在发生滚轮运动事件时加载帧图像一样。(也许有一种方法可以立即退出滚轮事件,从而减少加载时间?(这只是我对可能解决方案的猜测))。
以下是代码。非常感谢您的任何想法。
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);
        }

1
使用Swing的定时器Timer替代:while (true) { .. Thread.sleep(20); - Andrew Thompson
1
为了更快地得到帮助,请发布一个SSCCE - Andrew Thompson
1
你实现了Runnable接口,你是否打算在后台线程中运行run()方法?但事实并非如此,你直接调用了它。 - Christoph Walesch
@AndrewThompson,出现空白屏幕的原因是因为渲染循环刷新没有正确同步吗?在这种情况下,Swing Timer应该如何使用?(我看不出它如何与MWListener同步,因为那是用户输入。我对Java和编程一般都很新。抱歉让您详细解释。) - John Smith
一旦我看到SSCCE,我可能会有更多的信息给你,所以原因是... - Andrew Thompson
显示剩余2条评论
1个回答

3
缺少完整的示例,我无法重现您所描述的效果。您可以将您的代码与此示例进行比较,该示例不会出现明显的空白。
通常情况下,
- JPanel 默认情况下是双缓冲的;需要不同的缓冲策略是不寻常的。 - AnimationTest 演示了 Swing Timer 以及如何显示平均绘制周期。 - MouseAdapter 对于覆盖少量方法非常方便。 - 在可能的情况下,使用泛型参数来保证类型安全。

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://dev59.com/mWTWa4cB1Zd3GeqPG8wp#10970892
*/
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();
            }
        });
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接