JSlider changeListener不会更新 - Java

时间:2015-05-08 04:56:40

标签: java swing jpanel repaint jslider

我有一个分形树生成器,我正在尝试使滑块控制迭代次数,但我无法让它工作。此外,只要调用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 个答案:

答案 0 :(得分:2)

两个主要问题:

  1. 您将覆盖paint而不是paintComponent
  2. 您没有将super.paintComponent(g)(或者在您的情况下,super.paint(g))称为被覆盖方法中的第一件事。
  3. 这是您需要的:

    @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)。无需限制用户的空间。
    • 在框架上调用pack()而不是setSize(...)。后者太依赖于本地图形配置。
      • 您需要覆盖面板的getPreferredSize方法,以便为图形返回正确的尺寸。
    • 您的像素计算应调整为树对齐到面板的左上角,而不是从底部的任意位置启动它,这会导致您丢失大量的屏幕空间:

    enter image description here

    对评论的回应

      

    为什么要使用paintComponent

    见这些:

      

    public void paint(Graphics g)

         
        

    此方法实际上将绘画工作委托给三个受保护的方法:paintComponentpaintBorderpaintChildren。它们按列出的顺序调用,以确保子项出现在组件本身之上。 [...]只想专门化UI(外观)委托的paint方法的子类应该覆盖paintComponent

      

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

      

    调用超类构造函数的是什么?

    最好回答的是JLS:

      

    JLS 8.8.7。构造函数主体

         
        

    如果构造函数体不是以显式构造函数调用开始并且声明的构造函数不是原始类Object的一部分,那么构造函数体隐式地以超类构造函数调用“super();”开头,调用它的直接超类的构造函数,不带参数。

      

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