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);
}
}
两个主要问题:
- 您正在覆盖
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);
}
其他需要考虑的事项:
- 将滑块添加到
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()
什么都不做。
我有一个分形树生成器,我正在尝试制作一个滑块来控制迭代次数,但我无法让它工作。此外,只要调用 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);
}
其他需要考虑的事项:
- 将滑块添加到
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
, 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
并将滑块添加到面板,您会遇到滑块绘制问题,因为您忽略了 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()
什么都不做。