我可以将 2D 变换应用于 JavaFX 8 Canvas 上的形状吗?
Can I apply 2D transforms to shapes on a JavaFX 8 Canvas?
我正在将之前在 Swing 中完成的 class 移植到 JavaFX 8。它显示一个 UI 元素,看起来像一个模拟电压表,半圆被一个定期收集 "tic marks"。在 Swing 版本中,class 是 JPanel 的扩展,并且在 paintComponent(Graphics g) 中绘制了 tic 标记,如下所示:
private Line2D ticLine = new Line2D.Float(0, LINE_ROOT_Y, TIC_LENGTH, LINE_ROOT_Y);
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// Draw tic marks
if (ticCount > 0)
{
g2.draw(ticLine); // First tic
AffineTransform ticTrans = new AffineTransform();
// Draw all additional tics rotated around half circle
for (int i = 1; i < ticCount; i++)
{
ticTrans.rotate(Math.toRadians(ticGap),
METER_MIDDLE, METER_BASE_Y);
g2.draw(ticTrans.createTransformedShape(ticLine));
}
}
}
这很好用。
现在,对于 JavaFX,我正在使用 class 扩展 VBox。它包含 2 个堆叠的 Canvas 个对象。其中一个将绘制静态元素,如半圆和刻度线,另一个用于定期移动的仪表线。在第一个 Canvas 上,我希望使用与我在 Swing 版本中所做的类似的循环,以便轻松地在半圆周围的 ticCount # 个附加位置中重绘第一个刻度线。所以我尝试了以下编译和 运行 但只画了第一个刻度线:
// Called from the constructor:
MeterGC = MeterCanvas.getGraphicsContext2D();
Line ticLine = new Line(0, LINE_ROOT_Y, TIC_LENGTH, LINE_ROOT_Y);
// Draw tic marks
if (ticCount > 1)
{
MeterGC.setStroke(Color.GRAY);
MeterGC.setLineWidth(BASIC_LINE_WIDTH);
MeterGC.strokeLine(ticLine.getStartX(), ticLine.getStartY(),
ticLine.getEndX(), ticLine.getEndY());
Rotate ticTrans = new Rotate(Math.toRadians(ticGap), METER_MIDDLE, METER_BASE_Y);
for (int i = 1; i < ticCount; i++)
{
ticLine.getTransforms().add(ticTrans);
MeterGC.strokeLine(ticLine.getStartX(), ticLine.getStartY(),
ticLine.getEndX(), ticLine.getEndY());
}
}
可能像这样尝试 T运行sform Shape 对象只在绘制到场景时有效,而不是在 Canvas 上。或者我必须在 "ticLine.getTransforms().add(ticTrans)" 行之后做一些事情才能让它们应用于该行。我至少接近了吗?或者有更好的方法来完成我在这里尝试的事情吗?
你做错了什么
在您的示例代码中,您将转换应用于 Line
对象(您从不显示)。
如何修复
在 canvas 上划线之前,您需要 set the transform on the canvas GraphicsContext
。
示例代码
有关示例,请参阅:
- How to draw image rotated on JavaFX Canvas?
/**
* Sets the transform for the GraphicsContext to rotate around a pivot point.
*
* @param gc the graphics context the transform to applied to.
* @param angle the angle of rotation.
* @param px the x pivot co-ordinate for the rotation (in canvas co-ordinates).
* @param py the y pivot co-ordinate for the rotation (in canvas co-ordinates).
*/
private void rotate(GraphicsContext gc, double angle, double px, double py) {
Rotate r = new Rotate(angle, px, py);
gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
}
这是我修改后的 for 循环,效果很好。注意到在 JavaFX 中不再需要将 Rotate 中的角度转换为弧度也是让它工作的关键。
for (int i = 1; i < ticCount; i++)
{
Rotate ticTrans = new Rotate(ticGap * i, METER_MIDDLE, METER_BASE_Y);
MeterGC.setTransform(ticTrans.getMxx(), ticTrans.getMyx(), ticTrans.getMxy(),
ticTrans.getMyy(), ticTrans.getTx(), ticTrans.getTy());
MeterGC.strokeLine(ticLine.getStartX(), ticLine.getStartY(),
ticLine.getEndX(), ticLine.getEndY());
}
我正在将之前在 Swing 中完成的 class 移植到 JavaFX 8。它显示一个 UI 元素,看起来像一个模拟电压表,半圆被一个定期收集 "tic marks"。在 Swing 版本中,class 是 JPanel 的扩展,并且在 paintComponent(Graphics g) 中绘制了 tic 标记,如下所示:
private Line2D ticLine = new Line2D.Float(0, LINE_ROOT_Y, TIC_LENGTH, LINE_ROOT_Y);
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// Draw tic marks
if (ticCount > 0)
{
g2.draw(ticLine); // First tic
AffineTransform ticTrans = new AffineTransform();
// Draw all additional tics rotated around half circle
for (int i = 1; i < ticCount; i++)
{
ticTrans.rotate(Math.toRadians(ticGap),
METER_MIDDLE, METER_BASE_Y);
g2.draw(ticTrans.createTransformedShape(ticLine));
}
}
}
这很好用。
现在,对于 JavaFX,我正在使用 class 扩展 VBox。它包含 2 个堆叠的 Canvas 个对象。其中一个将绘制静态元素,如半圆和刻度线,另一个用于定期移动的仪表线。在第一个 Canvas 上,我希望使用与我在 Swing 版本中所做的类似的循环,以便轻松地在半圆周围的 ticCount # 个附加位置中重绘第一个刻度线。所以我尝试了以下编译和 运行 但只画了第一个刻度线:
// Called from the constructor:
MeterGC = MeterCanvas.getGraphicsContext2D();
Line ticLine = new Line(0, LINE_ROOT_Y, TIC_LENGTH, LINE_ROOT_Y);
// Draw tic marks
if (ticCount > 1)
{
MeterGC.setStroke(Color.GRAY);
MeterGC.setLineWidth(BASIC_LINE_WIDTH);
MeterGC.strokeLine(ticLine.getStartX(), ticLine.getStartY(),
ticLine.getEndX(), ticLine.getEndY());
Rotate ticTrans = new Rotate(Math.toRadians(ticGap), METER_MIDDLE, METER_BASE_Y);
for (int i = 1; i < ticCount; i++)
{
ticLine.getTransforms().add(ticTrans);
MeterGC.strokeLine(ticLine.getStartX(), ticLine.getStartY(),
ticLine.getEndX(), ticLine.getEndY());
}
}
可能像这样尝试 T运行sform Shape 对象只在绘制到场景时有效,而不是在 Canvas 上。或者我必须在 "ticLine.getTransforms().add(ticTrans)" 行之后做一些事情才能让它们应用于该行。我至少接近了吗?或者有更好的方法来完成我在这里尝试的事情吗?
你做错了什么
在您的示例代码中,您将转换应用于 Line
对象(您从不显示)。
如何修复
在 canvas 上划线之前,您需要 set the transform on the canvas GraphicsContext
。
示例代码
有关示例,请参阅:
- How to draw image rotated on JavaFX Canvas?
/**
* Sets the transform for the GraphicsContext to rotate around a pivot point.
*
* @param gc the graphics context the transform to applied to.
* @param angle the angle of rotation.
* @param px the x pivot co-ordinate for the rotation (in canvas co-ordinates).
* @param py the y pivot co-ordinate for the rotation (in canvas co-ordinates).
*/
private void rotate(GraphicsContext gc, double angle, double px, double py) {
Rotate r = new Rotate(angle, px, py);
gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy());
}
这是我修改后的 for 循环,效果很好。注意到在 JavaFX 中不再需要将 Rotate 中的角度转换为弧度也是让它工作的关键。
for (int i = 1; i < ticCount; i++)
{
Rotate ticTrans = new Rotate(ticGap * i, METER_MIDDLE, METER_BASE_Y);
MeterGC.setTransform(ticTrans.getMxx(), ticTrans.getMyx(), ticTrans.getMxy(),
ticTrans.getMyy(), ticTrans.getTx(), ticTrans.getTy());
MeterGC.strokeLine(ticLine.getStartX(), ticLine.getStartY(),
ticLine.getEndX(), ticLine.getEndY());
}