用户必须通过单击框架中的任意位置来选择4个点,然后程序将绘制Bezier曲线。我还提供了一种方法,可以在用户点击的位置绘制小圆圈,以便更容易查看。
我没有收到任何错误,但曲线没有显示出来。显然,我错过了一些东西,但我无法弄清楚是什么。
代码:
public class Splines {
public Splines(){
JFrame frame = new JFrame("Bezier curves");
frame.add(new draw());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class draw extends JPanel implements MouseListener{
Point[] controlPoints = new Point[100];
ArrayList<Point> punkter = new ArrayList<>();
int pSize = punkter.size();
public draw(){
addMouseListener(this);
}
@Override
public void mousePressed(MouseEvent e) {
if (pSize==4) drawBezier(pSize,4,getGraphics());
drawPoint(e);
pSize++;
}
//Method drawing points to visualize the control points
public void drawPoint(MouseEvent evt){
Graphics g = getGraphics();
Graphics2D g2d = (Graphics2D) g;
punkter.add(new Point(evt.getX(), evt.getY()));
g2d.setColor(Color.red);
g2d.fillOval(punkter.get(pSize).x, punkter.get(pSize).y, 5, 5);
controlPoints[pSize] = punkter.get(pSize);
}
public void drawBezier(int i, int n, Graphics g) {
int j;
double t, delta;
Point curvePoints[] = new Point[n + 1];
delta = 1.0 / n;
for (j = 0; j <= n; j++) {
t = j * delta;
curvePoints[j] = new Point();
curvePoints[j].x = (int) Math.round(controlPoints[i - 3].x * (1.0 - t) * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 2].x * 3.0 * t * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 1].x * 3.0 * t * t * (1.0 - t)
+ controlPoints[i].x * t * t * t);
curvePoints[j].y = (int) Math.round(controlPoints[i - 3].y * (1.0 - t) * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 2].y * 3.0 * t * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 1].y * 3.0 * t * t * (1.0 - t)
+ controlPoints[i].y * t * t * t);
}
g.setColor(Color.red);
for (j = 0; j < n; j++)
g.drawLine(curvePoints[j].x, curvePoints[j].y, curvePoints[j + 1].x, curvePoints[j + 1].y);
} // End drawBezier
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
}//End draw class
public static void main(String[] args) {
new Splines();
}//End main method
}//End Spline class
答案 0 :(得分:3)
虽然我强烈建议您考虑 MadProgrammer 和 Petter Friberg 指出的关于AWT
和Swing
中绘画的内容,这里的直接问题非常简单。
具体来说,它位于drawBezier()
方法中,该方法在第一次尝试访问NullPointerException
数组时引发controlPoints
。
当然,这是因为您尝试访问controlPoints[i]
,实际上,i
的值为4且controlPoints
为zero-based,这意味着你引用一个实际上不存在的元素(
controlPoints[4]
是null
)。在ThorbjørnRavnAndersen的答案here中查看有关数组初始化的更多信息。
现在解决方案应该是显而易见的:
curvePoints[j].x = (int) Math.round(controlPoints[i - 4].x * (1.0 - t) * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 3].x * 3.0 * t * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 2].x * 3.0 * t * t * (1.0 - t)
+ controlPoints[i - 1].x * t * t * t);
curvePoints[j].y = (int) Math.round(controlPoints[i - 4].y * (1.0 - t) * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 3].y * 3.0 * t * (1.0 - t) * (1.0 - t)
+ controlPoints[i - 2].y * 3.0 * t * t * (1.0 - t)
+ controlPoints[i - 1].y * t * t * t);
提供了这个:
我还在mousePressed()
进行了一次小编辑,以便在绘制贝塞尔曲线后返回:
@Override
public void mousePressed(MouseEvent e) {
if (pSize==4) {
drawBezier(pSize,4,getGraphics());
return;
}
drawPoint(e);
pSize++;
}
如果您进行此编辑,请尝试以下操作:
单击5次后,绘制Bezier曲线。现在,最小化窗口并恢复它。你会看到它是空白的。但是,如果再次单击内部,则会看到曲线重新出现(仅曲线;而不是控制点)。为什么会这样?
如果您能够回答这个问题,那么您将更快地了解评论中提到的一些问题以及 Petter Friberg的答案。
更新/附录 - 给予持久性
整个想法是找到一种方法让你的绘图持久化到任意用户动作,例如最小化,调整大小等。正如 Petter Friberg 指出的那样,这样做的方法是{{3 } paintComponent()
方法。
怎么做?嗯,实际上它很简单:
首先完全删除您的drawPoint()
方法。它的功能将分为mousePressed()
和paintComponent()
,如下所示:
@Override
public void mousePressed(MouseEvent e) {
if (pSize<4){
punkter.add(new Point(e.getX(), e.getY()));
controlPoints[pSize] = punkter.get(pSize);
pSize++;
repaint();
} else if (pSize==4){
// do other stuff, for example reset everything and start over
//pSize = 0;
//punkter.clear();
//for (int i= 0; i < controlPoints.length; i++){
// controlPoints[i]= null;
//}
//repaint();
//System.out.println("Reset");
}
}
和此:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.red);
for (int i=0; i<pSize; i++){
g2d.fillOval(punkter.get(i).x, punkter.get(i).y, 5, 5);
}
if (pSize==4) {
drawBezier(pSize,4,g);
}
}
值得指出的一点是,您仍然需要调用override paintComponent()
方法,这可以通过以下方式实现:super.paintComponent(g);
此外,getGraphics()
不再有效(如果有的话)作为drawBezier()
的参数;相反,使用了g
Graphics对象。
到目前为止,应用程序具有以前缺少的持久性。
请注意,代码中没有任何地方可以直接调用paintComponent()
。相反,它在您调用repaint()
时由图形子系统调用,或者系统决定是时候重绘。查看此内容的一种方法是将对repaint()
的调用注释掉。现在没有任何一个绘图功能的调用。这是否意味着什么都没有被画出来?或者,也许,您可以通过执行一些看似无关的动作来间接调用绘图?
答案 1 :(得分:2)
要绘制的JPanel
调用protected void paintComponent(Graphics gr)
我建议你override
这个方法,在用户点击的位置放置List<Point>
,并在此方法中绘制所有曲线。
Yuor代码就是这样的
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g)
...loop your points and draw your cruves on g
}
因此,当用户mousePressed
添加到List<Point>
并在repaint
JPanel
metod时
因此,您现在可以使用Graphics
,但是当您的swing应用程序刷新JPanel
时,会绘制您添加到其中的components
(没有)。基本上你正在将摆动上下文中的曲线绘制到Grafics g
,当paintComponent
中的摇摆被判定时,它将被重绘。