java - 如何增加 JPanel 重绘的频率?

标签 java swing jpanel paint graphics2d

我有一个简单的程序,可以绘制以一定速度和角度从原点发射的粒子的轨迹。我创建了 JPanel 的子类来处理它的绘制。每次重绘我的子类时,它都会获取当前时间和初始时间(均以毫秒为单位)之间的差异,将其转换为秒,然后找到粒子在该时间点应位于的 x 和 y 坐标,最后获取这些 x 和 y 坐标并将它们绘制在屏幕上。我的问题是,我的子类似乎以看起来很长的间隔重新绘制,因为只显示了几个点。

我的绘图方法:

private void doDrawing(Graphics g) {

    Dimension size = getSize();
    Insets insets = getInsets();
    int w = size.width - insets.left - insets.right;
    int h = size.height - insets.top - insets.bottom;

    Graphics2D g2d = (Graphics2D) g;
    g.drawString("Acceleration: -9.8m/s i", 0, 20);
    StringBuilder b = new StringBuilder();
    b.append("Current Velocity: ");
    b.append(String.valueOf(sim.getVector(tickSpeed
            * ((System.currentTimeMillis() - initTime) / 1000)).getMagnitude()));
    b.append(" m/s at ");
    b.append(String.valueOf(sim.getVector(tickSpeed
            * ((System.currentTimeMillis() - initTime) / 1000)).getDirection().getDirectionDeg()));
    b.append(" degrees");
    g.drawString(b.toString(), 0, 30);

    drawPreviousPoints(g2d);

    drawCurrentPointAndAppend(g2d, w, h);

    repaint();

}

private void drawCurrentPointAndAppend(Graphics2D g2d, int w, int h) {
    g2d.setColor(Color.red);
    double height = (length / w) * h;
    Vector2D c = sim.getVector(tickSpeed
            * ((System.currentTimeMillis() - initTime) / 1000));
    double currentX = w
            * ((sim.getX(tickSpeed
                    * ((System.currentTimeMillis() - initTime) / 1000))) / length);
    double currentY = h
            * (1 - ((sim.getY(tickSpeed
                    * ((System.currentTimeMillis() - initTime) / 1000))) / height));

    g2d.drawLine((int) currentX, (int) currentY, (int) currentX,
            (int) currentY);
    g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
            BasicStroke.JOIN_MITER));
    g2d.drawLine((int) currentX, (int) (currentY),
            (int) (currentX + w * (c.getX() / length)),
            (int) (currentY + (h *  -(c.getY() / height))));
    xList.add(currentX);
    yList.add(currentY);

}

private void drawPreviousPoints(Graphics2D g2d) {
    g2d.setColor(Color.blue);
    g2d.setStroke(new BasicStroke(7, BasicStroke.CAP_ROUND,
            BasicStroke.JOIN_ROUND));
    if (!xList.isEmpty()) {
        for (int i = 0; i < xList.size(); i++) {
            g2d.drawLine(xList.get(i).intValue(), yList.get(i).intValue(),
                    xList.get(i).intValue(), yList.get(i).intValue());
        }
    }

}

tickSpeed 只是一个用于加速或减慢粒子速度的变量。它运行良好;然而,动画看起来很断断续续。

  • 如何解决这种不稳定问题(让一切看起来更“流畅”)
  • 我应该在哪里调用repaint()?因为我觉得在我的绘图方法末尾调用它是不对的。

最佳答案

Swing 的一条重要规则 - 您无法控制绘制过程...

不要在paintComponent内执行这些计算。 paintComponent 旨在绘制 UI 的当前状态,并且可能会出于多种原因随时调用,其中大多数原因超出了您的控制范围。

相反,请考虑使用设置为定期重复的 javax.swing.Timer(40 毫秒是每秒 25 个滴答声)。

建立一个模型来跟踪当前已处理的粒子。当计时器计时时,计算粒子位置并更新它们,然后调用repaint

在您的 paintComponent 中,只需绘制模型的当前状态即可。

看看Concurrency in SwingHow to use Swing Timers了解更多详情

关于java - 如何增加 JPanel 重绘的频率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25614241/

相关文章:

Java - JTable - getSelectedRow() 中的数据错误

java - 在 BorderLayout 中换出中心 JPanel

java - 将焦点放在 JLayeredPane 中的 JPanel

java - 不能在 2 个数组列表上使用 equal

javascript - 如何让服务器返回一个 html 文件?

java - 我们可以直接用 guice@inject 注入(inject)一个类(没有实现接口(interface))吗

Java 跨驱动器移动文件会导致 DirectoryNotEmptyException

java - 带有 JSP 示例的简单 AJAX

java - 为什么这个方法允许一个double存储在Integer类型的ArrayList中?

java - 在世界地图上显示位置