我为主题标题道歉,它可能不完全表达我的想法,但我会尝试一下。如果有人知道什么是更好的标题,请建议编辑。
所以我想在按下按钮后创建矩形并为它们赋值。如果我知道要创建多少个矩形,那么一切都很简单明了。在这里,事情变得复杂 - 我按下按钮后得到矩形计数。
我将以一个例子来解释,所以它更清楚一点:
final ArrayList rectList = new ArrayList();
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(final ActionEvent event) {
ArrayList getFromMethodAnArrayList = methodWhichReturnsAnArrayList();
for (int i = 0; i<getFromMethodAnArrayList.size();i++){
rectList.add(new Rectangle(0,0,0,30));
}
}
});
HBox box1 = new HBox(1);
for (int i = 0; i<rectList.size();i++){
box1.getChildren().add(rectList.get(i));
}
此代码出错,因为首次加载时rectList为空。我如何排队将元素添加到HBox中,因此它将在对rectList进行估值后执行。
答案 0 :(得分:1)
我认为你可以通过删除ArrayList并在按钮事件发生时填充box1
来简化你的代码:
final HBox box1 = new HBox(1);
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(final ActionEvent event) {
ArrayList getFromMethodAnArrayList = methodWhichReturnsAnArrayList();
for (int i = 0; i<getFromMethodAnArrayList.size();i++){
box1.getChildren().add(new Rectangle(0,0,0,30));
}
}
});
如果您感兴趣的是并发性,那么阅读Concurrency in JavaFX会很好,尽管我认为这不是您发布的问题的正确解决方案。
答案 1 :(得分:1)
建议
你不需要在这里排队,你也不需要多线程,至少你现在已经描述过你的问题了 - 对实施的额外要求可能意味着两者的使用那些事情是必要的。
示例代码
示例代码的作用是定义项目源,这些项目是您要显示的内容的模型数据。当您单击“创建”按钮时,它将生成随机数量的新项目,每个项目具有随机数据值。这些项目将被放入队列中,后续例程将从队列中获取项目,读取其数据值并为项目数据创建适当的可视化表示(矩形)。它使用队列数据结构,但是一个简单的数组或列表就可以正常工作。
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Random;
// java 8 code
public class RectangleAddition extends Application {
private final Random random = new Random(42);
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
FlowPane flow = createItemContainer();
ScrollPane scroll = makeContainerScrollable(flow);
ItemSource itemSource = new ItemSource();
Button create = createItemControl(flow, scroll, itemSource);
VBox layout = createLayout(create, scroll);
Scene scene = new Scene(layout);
stage.setScene(scene);
stage.show();
}
private FlowPane createItemContainer() {
FlowPane flow = new FlowPane();
flow.setHgap(5);
flow.setVgap(5);
return flow;
}
/**
* The control will
* retrieve items from the source,
* add them to the scrollable pane,
* scroll the pane to the bottom on each addition.
*/
private Button createItemControl(Pane flow, ScrollPane scroll, ItemSource itemSource) {
Button create = new Button("Create Rectangles (keep pressing to create more)");
create.setOnAction(event -> {
addRectangles(flow, itemSource);
scroll.setVvalue(scroll.getVmax());
});
return create;
}
private VBox createLayout(Button create, ScrollPane scroll) {
VBox layout = new VBox(10, create, scroll);
layout.setStyle("-fx-padding: 10px;");
layout.setPrefSize(300, 300);
VBox.setVgrow(scroll, Priority.ALWAYS);
create.setMinHeight(Button.USE_PREF_SIZE);
return layout;
}
/**
* fetches some items from the source,
* creates rectangle nodes for them
* adds them to the container.
*/
private void addRectangles(Pane container, ItemSource itemSource) {
Queue<Item> items = itemSource.fetchNextItems();
while (!items.isEmpty()) {
Item item = items.remove();
Node rectangle = createRectangle(item);
container.getChildren().add(rectangle);
}
}
private Rectangle createRectangle(Item item) {
Rectangle rectangle = new Rectangle(item.size, item.size, item.color);
rectangle.setRotate(item.rotation);
return rectangle;
}
private ScrollPane makeContainerScrollable(FlowPane flow) {
ScrollPane scroll = new ScrollPane(flow);
scroll.setFitToWidth(true);
scroll.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
return scroll;
}
/** some model data for application items */
class Item {
// item will be colored according to rgb values from the (inclusive) range
// MIN_COLOR_VALUE to MIN_COLOR_VALUE + COLOR_RANGE - 1
private static final int MIN_COLOR_VALUE = 50;
private static final int COLOR_RANGE = 201;
// item will be sized from the (inclusive) range
// MIN_SIZE to MIN_SIZE + SIZE_RANGE - 1
private static final int MIN_SIZE = 5;
private static final int SIZE_RANGE = 21;
// item will be (z-axis) rotated from the (inclusive) range
// - ROTATE_SCOPE to + ROTATE_SCOPE
private static final int ROTATE_SCOPE = 10;
private Color color;
private int size;
private int rotation;
public Item() {
color = Color.rgb(
createColorComponent(),
createColorComponent(),
createColorComponent()
);
size = random.nextInt(SIZE_RANGE) + MIN_SIZE;
rotation = random.nextInt(ROTATE_SCOPE * 2 + 1) - ROTATE_SCOPE;
}
private int createColorComponent() {
return random.nextInt(COLOR_RANGE) + MIN_COLOR_VALUE;
}
}
/** a never-ending source of new items fetched in batches */
class ItemSource {
// will fetch between 1 and MAX_NUM_ITEMS_PER_FETCH (inclusive) items on each fetch call.
private static final int MAX_NUM_ITEMS_PER_FETCH = 5;
public Queue<Item> fetchNextItems() {
int numItems = random.nextInt(MAX_NUM_ITEMS_PER_FETCH) + 1;
Queue<Item> queue = new ArrayDeque<>(numItems);
for (int i = 0; i < numItems; i++) {
queue.add(new Item());
}
return queue;
}
}
}
关于多线程的思考
您可能希望实际使用多线程的不同实现是项目创建或从项目源获取需要很长时间。例如,您需要从网络,数据库或非常大的文件中读取项目数据。如果你没有多线程这样的东西,那么你会在等待I / O完成时冻结UI。一般规则是,如果您正在执行的操作将在不到六十分之一毫秒内完成,那么您可以在JavaFX UI线程上完成此操作而不会出现任何问题,因为UI中没有明显的延迟和卡顿,但如果它需要更长时间才能使用并发实用程序(使用比单线程代码更棘手)。
Java有许多可以使用的线程机制,但在许多情况下,使用JavaFX specific concurrency extensions是将多线程代码集成到JavaFX应用程序中的最佳方法。
如果您是从UI按需执行此操作,通常使用的适当并发实用程序将是JavaFX Task或Service接口。您可以阅读这些工具的文档,这些工具演示了诸如&#34;返回部分结果的任务的示例代码&#34; (这与你的问题有点类似)。
如果提供要消耗的项目的东西是一些长期运行的网络任务,其中项目被推送,而不是按需拉动,然后在其自己的线程中运行它并回调到JavaFX中通过platform.runLater()发出UI更新信号是最佳选择。另一个可以帮助这种情况的数据结构是BlockingQueue,如multi-chart creation code所示 - 但这是一个非常复杂的解决方案。
我想我的一部分意思是你可能不需要在你的情况下使用这些并发实用程序,你需要根据具体情况对其进行评估并使用最合适的解决方案。