【问题标题】:JSlider changeListener won't update - JavaJSlider changeListener 不会更新 - Java
【发布时间】:2015-07-18 21:52:04
【问题描述】:

我有一个分形树生成器,我试图让一个滑块控制迭代次数,但我无法让它工作。此外,每当调用 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);
    }
}

【问题讨论】:

    标签: java swing jpanel repaint jslider


    【解决方案1】:

    两个主要问题:

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

    对 cme​​ts 的回应

    为什么要使用paintComponent

    查看这些:

    public void paint(图形 g)

    这个方法实际上将绘画的工作委托给了三个受保护的方法:paintComponentpaintBorderpaintChildren。它们按列出的顺序调用,以确保子组件出现在组件本身的顶部。 [...] 只想专门化 UI(外观和感觉)委托的绘制方法的子类应该重写 paintComponent

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

    调用超类构造函数有什么作用?

    最好的答案是 JLS:

    JLS 8.8.7。构造函数体

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

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

    【讨论】:

    • 谢谢。另外,您能否提供一些关于为什么应该使用 paintComponent 以及调用超类构造函数的作用的见解?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    • 1970-01-01
    相关资源
    最近更新 更多