当 PopUp 完全展开时 JPanel 不可见

JPanel not turning visible when PopUp is fully expanded

我有一个像弹出窗口一样展开和收缩的弹出窗口 class。它扩展了 JPanel。

我已经覆盖了 JPanel 的典型可见性方法以选择是否应绘制 PopUp 对象。只有当弹出窗口完全展开时,JPanel 才应该可见。

然而,这是不起作用的部分。

这是相关的 PopUp class 代码。我添加了一些希望有所帮助的评论:

public class PopUp extends JPanel {

    /**
     * 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 expanding
     */
    private boolean isExpanding = false;
    /**
     * Whether or not the pop-up is visible
     */
    private boolean visible;

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

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

    /**
     * The currently used transform for the pop-up
     */
    private AffineTransform trans;

    /**
     * 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;
        this.borderWidth = 0;
        this.borderColor = null;
        popUp = new Rectangle2D.Double(0, 0, width, height);
        setBounds((int) Math.round(x), (int) Math.round(y), (int) Math.round(w), (int) Math.round(h));
        trans = new AffineTransform();
        //Centers the rectangle pop-up at the center of the given rectangle made by the given x, y, width, and height
        trans.translate(x + width/2 * (1 - (double) expansionStage/steps), y + height/2 * (1 - (double) expansionStage/steps));
        //Scales the rectangle based on the percentage it is expanded
        trans.scale((double) expansionStage/steps, (double) expansionStage/steps);
    }

    /**
     * Draws the pop-up
     * @param g     Graphics object from paintComponent
     */
    public final void draw(Graphics g) {
        //Expands pop-up one step
        if(isExpanding && visible)
            expansionStage = Math.min(expansionStage + 1, steps);
        //Contracts pop-up one step
        else if(visible)
            expansionStage = Math.max(expansionStage - 1, 0);
        //Resets pop-up size to 0
        else
            expansionStage = 0;
        if(visible) {
            //Sets the visibility of the JPanel to true if the pop-up is fully expanded (false otherwise)
            super.setVisible(expansionStage/steps == 1);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            AffineTransform trans = new AffineTransform();
            //Centers the rectangle pop-up at the center of the given rectangle made by the given x, y, width, and height
            trans.translate(x + width/2 * (1 - (double) expansionStage/steps), y + height/2 * (1 - (double) expansionStage/steps));
            //Scales the rectangle based on the percentage it is expanded
            trans.scale((double) expansionStage/steps, (double) expansionStage/steps);
            this.trans = trans;
            g2d.setColor(color);
            Shape transformed = trans.createTransformedShape(popUp);
            g2d.fill(transformed);
        }
        else
            super.setVisible(false);
    }

    /**
     * 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;
    }

    /**
     * Returns whether or not the pop-up is expanding
     * @return Whether or not the pop-up is expanding
     */
    public final boolean getExpanding() {
        return isExpanding;
    }

    /**
     * Returns the percentage that the pop-up has expanded
     * @return The percentage that the pop-up has expanded
     */
    public final double percentageExpanded() {
        return (double) expansionStage/steps;
    }

    /**
     * Different than JPanel.setVisible(boolean visible) in that it
     * only draws the PopUp if this is true, and the JPanel is visible
     * only when this is true and the popUp is expanded
     * @param visible   Whether or not the pop-up should be visible
     */
    @Override
    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    /**
     * Different than JPanel.isVisible() in that it
     * only draws the PopUp if this is true, and the JPanel is visible
     * only when this is true and the popUp is expanded
     * @return  Whether or not the pop-up should be visible
     */
    @Override
    public boolean isVisible() {
        return visible;
    }

    public boolean jPanelIsVisible() {
        return super.isVisible();
    }

}

我通过创建一个来设置它。然后,我将它添加到主 JPanel 并将其可见性设置为 true。

在主 JPanel 的 paintComponent() 方法中,我调用了 PopUp.draw(g)。

最后,当我希望它展开时我有 PopUp.setExpanding(true),当我希望它收缩时我有 PopUp.setExpanding(false)。

如果需要任何其他信息,请告诉我。

更新:

我打算使用 MadProgrammer 的 PopUp 版本的修改版本 class,但我想我会让大家知道真正的问题是什么。

当 MadProgrammer 认为可见性是问题所在时,他的想法是正确的。当我使用 super.setVisible() 时,它引用了我的 PopUp 的 isVisible() 方法,这很不幸。

所以,经过一番深入研究,我认为你最大的问题是 "visibility" 概念。

super.setVisible(expansionStage/steps == 1);,当expansionStage/steps不等于1时,会使组件不可见。

我放弃了可见性的概念并从 JPanel 中删除了继承,因为它没有增加任何好处并且导致了无穷无尽的问题。

我还将动画循环移动到 class 本身,并使用 update 方法独立于绘制过程更新状态,因为绘制可以出于多种原因随时发生,这可能会中断动画。

我还添加了一些方法来提供有关 class 是否完全展开或折叠的信息,这提供了一个触发点来确定何时应该停止动画。

在我看来(可怕的地方),你应该有一个"state"变量,其中包含expandedcollapsedexpandingcollapsing,来自您可以确定在不同时间应该发生什么。这也意味着您可以根据需要反转动画中间周期。

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private PopUp popUp;

        public TestPane() {
            popUp = new PopUp(10, 10, 180, 180, 10, Color.yellow);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    popUp.animate(TestPane.this);
                }
            });
        }

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

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            popUp.draw(g);
            g2d.dispose();
        }

    }

    public class PopUp {

        /**
         * 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 expanding
         */
        private boolean isExpanding = false;
        /**
         * Whether or not the pop-up is visible
         */
//      private boolean visible;

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

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

        /**
         * The currently used transform for the pop-up
         */
        private AffineTransform trans;

        private Timer timer;
        private Component parent;

        /**
         * 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;
//          this.borderWidth = 0;
//          this.borderColor = null;
            popUp = new Rectangle2D.Double(0, 0, width, height);
//          setBounds((int) Math.round(x), (int) Math.round(y), (int) Math.round(w), (int) Math.round(h));
            trans = new AffineTransform();
            //Centers the rectangle pop-up at the center of the given rectangle made by the given x, y, width, and height
            trans.translate(x + width / 2 * (1 - (double) expansionStage / steps), y + height / 2 * (1 - (double) expansionStage / steps));
            //Scales the rectangle based on the percentage it is expanded
            trans.scale((double) expansionStage / steps, (double) expansionStage / steps);

            timer = new Timer(10, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    update();
                    parent.repaint();
                }
            });
        }

        public void animate(Component parent) {
            this.parent = parent;
            setExpanding(isCollapsed());
            timer.start();
        }

        public void update() {
            //Expands pop-up one step
            if (isExpanding) {
                if (!isExpanded()) {
                    expansionStage = Math.min(expansionStage + 1, steps);
                } else {
                    timer.stop();
                }
            } //Contracts pop-up one step
            else {
                if (!isCollapsed()) {
                    expansionStage = Math.max(expansionStage - 1, 0);
                } else {
                    timer.stop();
                }
            }
        }

        public boolean isCollapsed() {
            return (((double) expansionStage / (double) steps) == 0);
        }

        public boolean isExpanded() {
            return (((double) expansionStage / (double) steps) == 1);
        }

        /**
         * Draws the pop-up
         *
         * @param g Graphics object from paintComponent
         */
        public final void draw(Graphics g) {
//          if (visible) {
            //Sets the visibility of the JPanel to true if the pop-up is fully expanded (false otherwise)

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            AffineTransform trans = new AffineTransform();
            //Centers the rectangle pop-up at the center of the given rectangle made by the given x, y, width, and height

            trans.translate(x + width / 2 * (1 - (double) expansionStage / steps), y + height / 2 * (1 - (double) expansionStage / steps));
            //Scales the rectangle based on the percentage it is expanded
            trans.scale((double) expansionStage / steps, (double) expansionStage / steps);
            this.trans = trans;
            g2d.setColor(color);
            Shape transformed = trans.createTransformedShape(popUp);
            g2d.fill(transformed);
//          } else {
////                setVisible(false);
//          }
        }

        /**
         * 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;
//          setVisible(expanding);
        }

        /**
         * Returns whether or not the pop-up is expanding
         *
         * @return Whether or not the pop-up is expanding
         */
        public final boolean getExpanding() {
            return isExpanding;
        }

        /**
         * Returns the percentage that the pop-up has expanded
         *
         * @return The percentage that the pop-up has expanded
         */
        public final double percentageExpanded() {
            return (double) expansionStage / steps;
        }

//      /**
//       * Different than JPanel.setVisible(boolean visible) in that it only draws
//       * the PopUp if this is true, and the JPanel is visible only when this is
//       * true and the popUp is expanded
//       *
//       * @param visible Whether or not the pop-up should be visible
//       */
//      public void setVisible(boolean visible) {
//          this.visible = visible;
//      }
//
//      /**
//       * Different than JPanel.isVisible() in that it only draws the PopUp if this
//       * is true, and the JPanel is visible only when this is true and the popUp
//       * is expanded
//       *
//       * @return Whether or not the pop-up should be visible
//       */
//      public boolean isVisible() {
//          return visible;
//      }
    }

}