我有一个分形树生成器,我试图让 slider 控制迭代次数,但我无法让它工作。此外,每当调用 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);
}
}
最佳答案
两个主要问题:
- 你凌驾于
paint
之上而不是paintComponent
. - 你没有调用
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);
}
其他需要考虑的事情:
- 将 slider 添加到框架的位置
BorderLayout.PAGE_START
而不是面板。如果将其添加到面板中,您可能会面临绘制 slider 所在位置的风险。 - 在面板上而不是框架上设置背景颜色。
- 无需调用
super()
在构造函数中,它是自动的。 -
setResizable(false)
一般应避免在框架上。无需限制用户的空间。 - 调用
pack()
在框架上而不是setSize(...)
。后者过于依赖本地显卡配置。- 您需要覆盖面板的
getPreferredSize
方法返回正确的绘图尺寸。
- 您需要覆盖面板的
- 您的像素计算应调整为使树与面板的左上角对齐,而不是从底部的任意位置开始,这会导致您损失大量屏幕空间:<
回复评论
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)
block 引用>This method actually delegates the work of painting to three protected methods:
paintComponent
,paintBorder
, andpaintChildren
. 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 overridepaintComponent
.如果您覆盖
paint
,您就会看到这一点并将 slider 添加到面板中,您遇到了 slider 绘制问题,因为您忽略了paintChildren
.What calling the superclass constructor does?
最好的回答是 JLS:
JLS 8.8.7. Constructor Body
block 引用>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()
什么都不做。
关于java - JSliderchangeListener不会更新 - Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30116062/