【问题标题】:Java graphics isn't repaintingJava 图形不会重绘
【发布时间】:2013-06-02 20:19:55
【问题描述】:

我想添加一个功能,这样当鼠标移到一个按钮上时,它会添加一个阴影。目前我只是想让机制工作。我的游戏循环调用了一个我知道有效的更新方法,但无论如何都在这里

    public void updateManager(double delta){
    mhandler.updateCoordinates();
    if(mhandler.getX() >= 144 && mhandler.getX() <= 444 && mhandler.getY() >= 784 && mhandler.getY() <= 980){
        oversp = true;
    }else{
        oversp = false;
    }
}

mhandler 是我命名的 MouseHandler 类。 然后我有我的渲染方法

    public void render(){
    repaint();
}

然后是我的绘画方法

    public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    if(oversp){
        System.out.println("Is over button");
        g2d.setColor(Color.RED);
        g2d.fillRect(144, 784, 300, 169);
    }else{
        System.out.println("Not over button");
        g2d.setColor(Color.BLACK);
        g2d.fillRect(144, 784, 300, 169);
    }
}

当我运行程序时,即使我在游戏循环中不断调用 render(),它也只会打印两次 not over button。我真的不知道为什么它不重绘。任何帮助都非常感谢!

这就是我检测鼠标坐标的方式

    private int x,y;

public MouseHandler(){
    x = 0;
    y = 0;
}

public void updateCoordinates(){
    PointerInfo a = MouseInfo.getPointerInfo();
    Point b = a.getLocation();
    x = (int) b.getX();
    y = (int) b.getY();
}

public int getX(){
    return x;
}

public int getY(){
    return y;
}

游戏循环代码

    public static void MenuLoop() {
    long lastLoopTime = System.nanoTime();
    final int TARGET_FPS = 60;
    final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
    long lastFpsTime = 0;
    int fps = 0;
    while (isrunning) {
        long now = System.nanoTime();
        long updateLength = now - lastLoopTime;
        lastLoopTime = now;
        double delta = updateLength / ((double) OPTIMAL_TIME);

        lastFpsTime += updateLength;
        fps++;

        if (lastFpsTime >= 1000000000) {
            System.out.println("(FPS: " + fps + ")");
            lastFpsTime = 0;
            fps = 0;
        }

        menu.render();
        menu.updateManager(delta);


        try {
            Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000);
        } catch (Exception e) {

        }
    }

}public static void MenuLoop() {
    long lastLoopTime = System.nanoTime();
    final int TARGET_FPS = 60;
    final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
    long lastFpsTime = 0;
    int fps = 0;
    while (isrunning) {
        long now = System.nanoTime();
        long updateLength = now - lastLoopTime;
        lastLoopTime = now;
        double delta = updateLength / ((double) OPTIMAL_TIME);

        lastFpsTime += updateLength;
        fps++;

        if (lastFpsTime >= 1000000000) {
            System.out.println("(FPS: " + fps + ")");
            lastFpsTime = 0;
            fps = 0;
        }

        menu.render();
        menu.updateManager(delta);


        try {
            Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000);
        } catch (Exception e) {

        }
    }

}

【问题讨论】:

  • 会不会是你的游戏循环阻塞了gui线程?
  • 这肯定是您如何检测鼠标是在按钮内部还是外部的问题,但由于我们没有相应的代码,因此目前无法进行故障排除。另外 - 最好将鼠标位置与按钮本身返回的坐标进行比较,而不是使用 X 和 Y 的绝对值。
  • Swing 绘制管理器将合并您的 repaint() 请求,如果它们来得快且关闭。所以repaints 发生的数量比预期的要少。
  • 这段代码错过了paintComponent中的super.paintComponent(g)(第一行)
  • 如果您在EDT 的无限循环中调用render,EDT 将被阻塞并且GUI 将无响应(正如@Heuster 已经提到的)。如果这就是你的游戏循环的样子,你应该使用Swing timer。在任何情况下,您都可以发布游戏循环的代码。

标签: java graphics awt repaint event-dispatch-thread


【解决方案1】:

Event Dispatch Thread 包含一个队列,所有 AWT 事件都添加到该队列中。每当您调用repaint 时,都会在事件调度线程上排队绘制事件。

因此,如果您在事件调度线程上处于无限循环中,那么这些绘制事件将永远排队,等待无限循环结束。这就是为什么永远不会调用 paintComponent 的原因。

解决方案是用Swing timer 替换无限循环。

Timer timer = new Timer(1000 / TARGET_FPS, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        //...
    }
});
timer.start();

【讨论】:

    猜你喜欢
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多