几天前,我请你帮助我,因为我无法逐个像素地显示圆圈的图形(图形卡住)。 @James_D找到了解决方案并告诉我这是因为后台线程试图修改UI。实际上,我有一个GraphicEngine
类扩展Service
:这个类是这个背景线程,它的目的是计算和修改图像(现在它的目的只是计算圆圈' s像素)。
好吧,最后,感谢@James_D,我现在有一些课程:
GraphicEngine
,ImageAnimation
,其中包含绘图动画DialogCreationOfCircularGradation
,这是一个包含按钮的对话框"好的,画圆圈!"并处理此事件。以下来源包含我的程序对用户事件的回答"画一个圆圈"。它获得了几个Textfield
的输入并将其提供给GraphicsEngine
。此外,它要求后者计算圆的像素,并要求ImageAnimation
在GraphicsEngine
完成的计算过程中逐像素地显示计算。
CLASS DialogCreationOfCircularGradation
public void dialogHandleEvents() {
Optional r = this.showAndWait();
if(r.isPresent() && r.get() == ButtonType.OK) { // The user clicks on "OK, draw the circle !"
int radius = Integer.parseInt(this.dialog_field_radius.getText());
[...]
this.gui.getImageLoader().loadImageFromUsersPreferences(x0 + thickness + 2*radius, y0 + thickness + 2*radius);
this.gui.getGraphicEngine().setOperationToDo("Circle");
this.gui.getGraphicEngine().setRadius(radius);
[...]
this.gui.getGraphicEngine().restart();
this.gui.getImageAnimation().start();
}
}
以下代码为GraphicsEngine
个。如您所见,特别是一个重要变量在循环算法期间递增:其名称为counter_max
。为什么这个变量很重要?因为在课程ImageAnimation
中使用它是必要的。在GraphicsEngine
之后查看其来源。
CLASS GraphicEngine
public class GraphicEngine extends Service<Void> {
private int image_width, image_height;
private PixelReader pixel_reader;
private BlockingQueue<Pixel> updates;
private String operation_to_do;
private int radius; [...]
public void setOperationToDo(String operation_to_do) {
this.operation_to_do = operation_to_do;
}
public Task<Void> createTask() {
return new Task<Void>() {
protected Void call() {
switch(operation_to_do) {
[...]
case "Circle" :
traceCircularGradation();
break;
}
return null;
}
};
}
private void traceCircularGradation() {
double w = 2 * 3.141, precision = 0.001;
long counter_max = 0;
int x, y;
this.gui.getImageAnimation().setMax(counter_max);
double[] rgb_gradation;
for (double current_thickness = 0; current_thickness <= this.thickness; current_thickness++) {
for (double angle = 0; angle <= w; angle += precision) {
x = (int) ((current_thickness + radius) * Math.cos(angle) + x0);
y = (int) ((current_thickness + radius) * Math.sin(angle) + y0);
if(x >= 0 && y >= 0) {
counter_max++;
rgb_gradation = PhotoRetouchingFormulas.chromatic_gradation(angle, w);
updates.add(new Pixel(x, y, Color.color(rgb_gradation[0], rgb_gradation[1], rgb_gradation[2])));
}
}
}
this.gui.getImageAnimation().setMax(counter_max);
}
变量counter_max
用于ImageAnimation
(其名称已更改,名称为max
)。它在上一个if
:if (count >= max)
中很有用。
max
/ counter_max
表示修改后的像素数。我无法用image_width * image_height
替换它,因为在圆算法中,只绘制/修改了圆的像素。图像的其他像素不是。
所以我要像counter_max
循环中那样计算for
,然后将其提供给ImageAnimation
,或者找到一个数学公式来确定它{{1} }}。在第一种情况下,圆圈的显示不起作用。
如果存在一个公式,那将是非常完美的。
CLASS ImageAnimation
for
答案 0 :(得分:0)
如果您稍后需要计算max
,则无法将其初始化为零(因为如果在将其设置为“正确”值之前进行任何更新,则count
将超过max
你将停止动画)。因此,只需将其初始化为永远无法达到的内容,例如Long.MAX_VALUE
。
相关地,由于您从多个线程访问max
,您应该同步对它的访问,或者(更好)使用AtomicLong
。即。
public class ImageAnimation extends AnimationTimer {
private Gui gui;
private AtomicLong max;
private long count, start;
ImageAnimation (Gui gui) {
this.gui = gui;
this.count = 0;
this.start = -1;
this.max = new AtomicLong(Long.MAX_VALUE);
}
public void setMax(long max) {
this.max.set(max);
}
@Override
public void handle(long timestamp) {
if (start < 0) {
start = timestamp ;
return ;
}
WritableImage writable_image = this.gui.getWritableImage();
BlockingQueue<Pixel> updates = this.gui.getUpdates();
while (timestamp - start > (count* 5_000_000) / (writable_image.getWidth()) && ! updates.isEmpty()) {
Pixel update = updates.remove();
count++;
writable_image.getPixelWriter().setColor(update.getX(), update.getY(), update.getColor());
}
if (count >= max.get()) {
this.count = 0;
this.start = -1;
this.max.set(Long.MAX_VALUE);
stop();
}
}
public void startAnimation() {
this.start();
}
}