JSlider changeListener 不会更新 - Java

JSlider changeListener won't update - Java

我有一个分形树生成器,我正在尝试制作一个滑块来控制迭代次数,但我无法让它工作。此外,只要调用 repaint() 方法,布局就会变得混乱。关于如何解决这个问题有什么想法吗?

public class FractalTree extends JPanel implements ChangeListener {

    static JSlider slider = new JSlider(0,12);

    static  int slideVal=7;
    public FractalTree()
    {
        super();
        slider.addChangeListener(this);
    }

    public void paint(Graphics g)
    {
        g.setColor(Color.green);
        drawTree(g, 400, 750, 200, Math.toRadians(-90), Math.toRadians(45), slideVal); //Don't let # of iterations exceed 12, it is useless
    }

    private void drawTree(Graphics g, int x1, int y1, double l, double t, double dt, double iterations) {
        if (iterations > 0) {
            int x2 = x1 + (int) (l * Math.cos(t));
            int y2 = y1 + (int) (l * Math.sin(t));
            g.drawLine(x1, y1, x2, y2);
            drawTree(g, x2, y2, l / 1.5, t + dt, Math.PI / 4, iterations - .5);
            drawTree(g, x2, y2, l / 1.5, t - dt, Math.PI / 4, iterations - .5);
        }
    }

    @Override
    public void stateChanged(ChangeEvent e) {
        slideVal=slider.getValue();
        repaint();
    }

    public static void main(String[] args) {
        JFrame t = new JFrame("Some swaggy fractal shit");
        FractalTree tree = new FractalTree();
        slider.setValue(slideVal);
        slider.setMinorTickSpacing(1);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);

        tree.add(slider);
        t.add(tree);
        t.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        t.setResizable(false);
        t.setLocationByPlatform(true);
        t.setSize(800, 800);
        t.setBackground(Color.black);
        t.setVisible(true);
    }
}

两个主要问题:

  1. 您正在覆盖 paint 而不是 paintComponent
  2. 您没有将 super.paintComponent(g)(或者在您的情况下,super.paint(g))作为重写方法中的第一件事。

这是你需要的:

@Override
public void paintComponent(Graphics g) {

    super.paintComponent(g);
    g.setColor(Color.green);
    drawTree(g, 400, 750, 200, Math.toRadians(-90), Math.toRadians(45), slideVal);
}

其他需要考虑的事项:

  • 将滑块添加到 BorderLayout.PAGE_START 位置的框架而不是面板。如果将其添加到面板,则可能会在滑块所在的位置进行绘制。
  • 在面板而不是框架上设置背景颜色。
  • 不需要在构造函数中调用super(),它是自动的。
  • setResizable(false) 通常应避免在框架上。无需限制用户的space.
  • 在框架上调用 pack() 而不是 setSize(...)。后者过于依赖本地图形配置。
    • 您需要重写面板的 getPreferredSize 方法以 return 绘图的正确尺寸。
  • 您的像素计算应调整为使树与面板的左上角对齐,而不是从底部的任意位置开始,这会导致您损失大量屏幕空间:

回复评论

Why paintComponent should be used?

查看这些:

  • paintComponent() vs paint() and JPanel vs Canvas in a paintbrush-type GUI
  • Difference between paint() and paintcomponent()?

public void paint(Graphics g)

This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren. They're called in the order listed to ensure that children appear on top of component itself. [...] A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.

您看到如果您覆盖 paint 并将滑块添加到面板,您会遇到滑块绘制问题,因为您忽略了 paintChildren

What calling the superclass constructor does?

最好的答案是 JLS:

JLS 8.8.7. Constructor Body

If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.

所以调用 super() 什么都不做。