【问题标题】:PopUp Class Seems To Speed Up AnimationsPopUp 类似乎可以加快动画速度
【发布时间】:2018-04-09 09:02:04
【问题描述】:

我有一个名为 PopUp 的类,它是一个 JPanel,当它被激活时,它会根据中心给出的参数展开到给定的大小和位置,并在单击时以相同的方式收缩。

由于某种原因,当 PopUp 扩展和收缩时,共享同一个 JPanel 的动画会加速。我在使用 PopUp 课程的两个程序中见证了这一点。

以下是我认为相关的代码:

/**
 * The {@code PopUp} class is a JPanel that expands to the rectangle
 * created from the given x, y, width and height that expands from
 * the center of the rectangle.
 * <p>
 * Here is an example of how the {@code PopUp} object can be initialized:
 * <blockquote><pre>
 *     PopUp pu = new PopUp(25, 25, 575, 575, 25, Color.GRAY);
 * </pre></blockquote>
 * <p>
 * The class {@code PopUp} includes methods for drawing the pop-up;
 * choosing whether the pop-up is expanding or not; getting the
 * percentage that the pop-up is expanded; and getting the maximum x, y,
 * width, and height
 *
 * @author  Gigi Bayte 2
 */
public class PopUp extends JPanel implements MouseListener {
    private static final long serialVersionUID = 1L;

    /**
     * Expanded x coordinate
     */
    private double x;
    /**
     * Expanded y coordinate
     */
    private double y;
    /**
     * Expanded width value
     */
    private double width;
    /**
     * Expanded height value
     */
    private double height;

    /**
     * Number of steps until fully expanded
     */
    private int steps;
    /**
     * This divided by steps is the percentage the pop-up is expanded
     */
    private int expansionStage = 0;

    /**
     * Whether or not the pop-up is expansing
     */
    private boolean isExpanding = false;

    /**
     * Color of the pop-up
     */
    private Color color;

    /**
     * The rectangle that represents the bounds of the pop-up
     */
    private Rectangle2D popUp;

    /**
     * Initializes a newly created {@code PopUp} with a uniform color
     * @param x                 The x coordinate of the expanded pop-up
     * @param y                 The y coordinate of the expanded pop-up
     * @param w                 The width of the expanded pop-up
     * @param h                 The height of the expanded pop-up
     * @param expansionSteps    The number of steps until fully expanded
     * @param popUpColor        The color of the pop-up
     */
    public PopUp(double x, double y, double w, double h, int expansionSteps, Color popUpColor) {
        this.x = x;
        this.y = y;
        width = w;
        height = h;
        color = popUpColor;
        steps = expansionSteps;
        popUp = new Rectangle2D.Double(0, 0, width, height);
        addMouseListener(this);
    }

    /**
     * Draws the pop-up
     * @param g     Graphics object from paintComponent
     */
    public final void draw(Graphics g) {
        if(isExpanding)
            expansionStage = Math.min(expansionStage + 1, steps);
        else
            expansionStage = Math.max(expansionStage - 1, 0);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        AffineTransform trans = new AffineTransform();
        trans.translate(x + width/2 * (1 - (double) expansionStage/steps), y + height/2 * (1 - (double) expansionStage/steps));
        trans.scale((double) expansionStage/steps, (double) expansionStage/steps);
        setBounds((int) trans.getTranslateX(), (int) trans.getTranslateY(), (int) (width * expansionStage/steps), (int) (height * expansionStage/steps));
        g2d.setColor(color);
        Shape transformed = trans.createTransformedShape(popUp);
        g2d.fill(transformed);
    }

    /**
     * Sets whether the pop-up is expanding or not
     * @param expanding    Whether or not the pop-up should expand
     */
    public final void setExpanding(boolean expanding) {
        isExpanding = expanding;
    }

    @Override
    public final void mouseClicked(MouseEvent e) {
        isExpanding = false;
    }
}

这是一个要运行的测试类:

public class Test extends JPanel implements ActionListener, MouseListener {
    private static final long serialVersionUID = 1L;

    private static PopUp popUp;
    private int stringX = 610;
    private int stringCounter = 0;

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(600, 600);

        Test t = new Test();
        t.setBounds(0, 0, 600, 600);
        frame.add(t);
        t.setVisible(true);

        Timer timer = new Timer(5, t);

        popUp = new PopUp(100, 100, 400, 400, 100, Color.WHITE);
        frame.add(popUp);
        popUp.setVisible(true);

        timer.start();

        frame.addMouseListener(t);
        frame.setLayout(null);
        frame.setUndecorated(true);
        frame.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, 600, 600);
        popUp.draw(g);
        g.setColor(Color.WHITE);
        g.drawString("This is a test", stringX, 580);
        if(++stringCounter % 3 == 0) {
            --stringX;
            stringCounter = 0;
        }
        if(stringX == -10 - g.getFontMetrics().stringWidth("This is a test"))
            stringX = 610;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        popUp.setExpanding(!popUp.getExpanding());
    }

    @Override
    public void mousePressed(MouseEvent e) {}

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

}

从上面的例子可以看出,每次弹出窗口扩大或收缩时,文本从右向左滚动都会加快速度。

【问题讨论】:

  • 这是接收到调用paintComponent()的重复更新事件时的预期行为;调整此AnimaitonTest 的大小以重现效果;有关更多详细信息,请edit 您的问题包括一个 minimal reproducible example 来展示您描述的问题。
  • 完成! @trashgod
  • 抱歉,没时间补缺。您的ActionListener 何时被调用?另见Initial Threads
  • 只要计时器计时,就会调用它。我会查看您发送的链接。 @trashgod
  • @trashgod 也许你可以帮我填写答案中的缺失部分?

标签: java swing timer jpanel graphics2d


【解决方案1】:

这是接收到调用paintComponent() 的重复更新事件时的预期行为;调整此AnimationTest 的大小以重现效果。

为什么重复的更新事件会导致这种情况?其背后的逻辑是什么?

在您的 draw() 方法中每次调用 setBounds() 都会“使组件层次结构无效”。 Component API 确保

当层次结构失效时,例如在更改组件的边界之后,或者在容器中添加/删除组件之后,整个层次结构必须随后通过在最顶层无效容器上调用的 Container.validate() 方法进行验证层次结构。

因为validate() 方法“可能是一个相当耗时的操作”,您可以“推迟对层次结构的验证,直到完成一组与布局相关的操作”,如您所显示的here;或者您可以使用javax.swing.Timer 调整动画的节奏,如图here

【讨论】:

    【解决方案2】:

    嗯,我发现了问题。罪魁祸首是这里的行:

    setBounds((int) trans.getTranslateX(), (int) trans.getTranslateY(), (int) (width * expansionStage/steps), (int) (height * expansionStage/steps));
    

    显然,将 JPanel 快速连续缩放到不同大小会导致一些速度扭曲,原因我不知道。我很感激对此答案进行编辑,并对这种现象做出更好的解释。

    我只是为 JPanel 设置了一个静态大小,然后让图形完成其余的工作。

    【讨论】:

    • here 所述,“重复更新事件……调用 paintComponent()。”
    • 问题是反复调整 JPanel 的大小。删除上面的行后,我仍然有一个 Timer 反复调用paintComponent(),它工作正常。 @trashgod
    • 在调整上述AnimationTest 的大小时会看到相同的效果。
    • @trashgod 我明白了。为什么重复的更新事件会导致这种情况?其背后的逻辑是什么?
    猜你喜欢
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多