在 JavaFX 中动态添加节点
Dynamically adding nodes in JavaFX
我正在尝试构建一个在 JavaFX 中实现群聊的聊天应用程序。我想在边框窗格内创建一个滚动窗格,它将包含用户所属的所有组。组图标 (ImageViews) 需要在用户加入时动态添加(不能在 Scene Builder 中完成)到滚动窗格(在 HBox 内部)。
目前我正在使用一个 SceneController class,它负责所有舞台和场景的变化。
package com.ong.Controllers;
import com.ong.Main;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.HashMap;
public class ScreenController {
private static HashMap<String, Scene> screenMap = new HashMap<>();
private static Stage main;
public ScreenController(Stage _main){
main = _main;
}
public static void addScreen(String name, FXMLLoader fxmlLoader){
Scene scene = null;
try {
scene = new Scene(fxmlLoader.load());
} catch (IOException e) {
e.printStackTrace();
}
screenMap.put(name,scene);
}
public static void addScene(String name, Scene scene){
screenMap.put(name,scene);
}
public static void removeScreen(String name){
screenMap.remove(name);
}
public static void setMinimumDimensions(int width, int height){
main.setMinWidth(width);
main.setMinHeight(height);
}
public static void setMaximized(boolean full){
main.setMaximized(full);
}
public static void activate(String name){
main.setScene(screenMap.get(name));
main.getIcons().add(new Image(Main.class.getResource("Images/not_logo.png").toString()));
main.setTitle(name);
main.show();
}
}
我已经创建了一个 FXML 文件(使用场景生成器),其中包含边框窗格和一个滚动窗格作为顶部子项。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" xmlns="http://javafx.com/javafx/11.0.2" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ong.Controllers.HomepageController">
<top>
<ScrollPane fx:id="groupsMenuScrollPane" hbarPolicy="NEVER" prefHeight="62.0" prefWidth="1920.0" stylesheets="@../CSS/groups_menu.css" vbarPolicy="NEVER" BorderPane.alignment="CENTER" />
</top>
</BorderPane>
我的计划是将所有组(在初始化时)填充到页面控制器中的滚动窗格。
package com.ong.Controllers;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.shape.Circle;
import java.net.URL;
import java.util.ResourceBundle;
public class HomepageController implements Initializable {
@FXML
private ScrollPane groupsMenuScrollPane;
@FXML
private BorderPane borderPane;
@Override
public void initialize(URL location, ResourceBundle resources) {
final ImageView imageView = new ImageView("com/ong/Images/not_logo.png");
final Circle clip = new Circle(300, 200, 200);
imageView.setClip(clip);
HBox hbox = new HBox();
hbox.getChildren().add(imageView);
groupsMenuScrollPane.setContent(hbox);
borderPane.setTop(groupsMenuScrollPane);
Scene scene = new Scene(borderPane);
ScreenController.addScene("Homepage", scene);
ScreenController.activate("Homepage");
}
}
我已经尝试使用更新后的边框窗格创建场景,但出现错误“borderPane 已设置为另一个场景的根”。我还尝试直接更改已存在场景的根,但在这种情况下我得到了 NullPointerException。
能否请您告知将节点动态添加到滚动窗格的最佳方式。如果您对项目结构提出意见,我将不胜感激。
你的问题和问题是不同的问题。
针对你的问题。动态添加您想要查看 ListView 的元素。
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ListView.html
至于你的问题。场景只能有一个根节点。在此根目录中,您应该有边界窗格,其中应该是您的 ListView。
Could you please advise which is the best way to add Nodes dynamically to a Scroll Pane.
您需要引用 ScrollPane
的内容(在本例中为 HBox
),以及向其中添加内容的方法:
public class HomepageController implements Initializable {
@FXML
private ScrollPane groupsMenuScrollPane;
@FXML
private BorderPane borderPane;
private HBox groupContainer ;
@Override
public void initialize(URL location, ResourceBundle resources) {
final ImageView imageView = new ImageView("com/ong/Images/not_logo.png");
final Circle clip = new Circle(300, 200, 200);
imageView.setClip(clip);
groupContainer = new HBox();
groupContainer.getChildren().add(imageView);
groupsMenuScrollPane.setContent(groupContainer);
// this is not needed since it's already done in FXML:
// borderPane.setTop(groupsMenuScrollPane);
// ...
}
public void addGroup(...) {
// not sure exactly what you want to add, but for example,
// to add a new image view you would do:
ImageView imageView = new ImageView(...);
groupContainer.getChildren().add(imageView);
}
}
加载 FXML 时,保留对控制器的引用:
FXMLLoader loader = new FXMLLoader(getClass().getResource(...));
Parent root = loader.load();
HomepageController controller = loader.getController();
然后您可以使用
向滚动窗格添加内容
controller.addGroup(...);
如另一个答案中所述,ListView
可能是更好的方法。
您可能还应该考虑 MVC 方法(例如,参见 ),其中模型使用 ObservableList<...>
来存储组列表。控制器可以观察该列表并在它更改时修改滚动窗格的内容。然后你所要做的就是通过模型向列表中添加一些东西。
我正在尝试构建一个在 JavaFX 中实现群聊的聊天应用程序。我想在边框窗格内创建一个滚动窗格,它将包含用户所属的所有组。组图标 (ImageViews) 需要在用户加入时动态添加(不能在 Scene Builder 中完成)到滚动窗格(在 HBox 内部)。
目前我正在使用一个 SceneController class,它负责所有舞台和场景的变化。
package com.ong.Controllers;
import com.ong.Main;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.HashMap;
public class ScreenController {
private static HashMap<String, Scene> screenMap = new HashMap<>();
private static Stage main;
public ScreenController(Stage _main){
main = _main;
}
public static void addScreen(String name, FXMLLoader fxmlLoader){
Scene scene = null;
try {
scene = new Scene(fxmlLoader.load());
} catch (IOException e) {
e.printStackTrace();
}
screenMap.put(name,scene);
}
public static void addScene(String name, Scene scene){
screenMap.put(name,scene);
}
public static void removeScreen(String name){
screenMap.remove(name);
}
public static void setMinimumDimensions(int width, int height){
main.setMinWidth(width);
main.setMinHeight(height);
}
public static void setMaximized(boolean full){
main.setMaximized(full);
}
public static void activate(String name){
main.setScene(screenMap.get(name));
main.getIcons().add(new Image(Main.class.getResource("Images/not_logo.png").toString()));
main.setTitle(name);
main.show();
}
}
我已经创建了一个 FXML 文件(使用场景生成器),其中包含边框窗格和一个滚动窗格作为顶部子项。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="borderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" xmlns="http://javafx.com/javafx/11.0.2" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ong.Controllers.HomepageController">
<top>
<ScrollPane fx:id="groupsMenuScrollPane" hbarPolicy="NEVER" prefHeight="62.0" prefWidth="1920.0" stylesheets="@../CSS/groups_menu.css" vbarPolicy="NEVER" BorderPane.alignment="CENTER" />
</top>
</BorderPane>
我的计划是将所有组(在初始化时)填充到页面控制器中的滚动窗格。
package com.ong.Controllers;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.shape.Circle;
import java.net.URL;
import java.util.ResourceBundle;
public class HomepageController implements Initializable {
@FXML
private ScrollPane groupsMenuScrollPane;
@FXML
private BorderPane borderPane;
@Override
public void initialize(URL location, ResourceBundle resources) {
final ImageView imageView = new ImageView("com/ong/Images/not_logo.png");
final Circle clip = new Circle(300, 200, 200);
imageView.setClip(clip);
HBox hbox = new HBox();
hbox.getChildren().add(imageView);
groupsMenuScrollPane.setContent(hbox);
borderPane.setTop(groupsMenuScrollPane);
Scene scene = new Scene(borderPane);
ScreenController.addScene("Homepage", scene);
ScreenController.activate("Homepage");
}
}
我已经尝试使用更新后的边框窗格创建场景,但出现错误“borderPane 已设置为另一个场景的根”。我还尝试直接更改已存在场景的根,但在这种情况下我得到了 NullPointerException。
能否请您告知将节点动态添加到滚动窗格的最佳方式。如果您对项目结构提出意见,我将不胜感激。
你的问题和问题是不同的问题。
针对你的问题。动态添加您想要查看 ListView 的元素。 https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ListView.html
至于你的问题。场景只能有一个根节点。在此根目录中,您应该有边界窗格,其中应该是您的 ListView。
Could you please advise which is the best way to add Nodes dynamically to a Scroll Pane.
您需要引用 ScrollPane
的内容(在本例中为 HBox
),以及向其中添加内容的方法:
public class HomepageController implements Initializable {
@FXML
private ScrollPane groupsMenuScrollPane;
@FXML
private BorderPane borderPane;
private HBox groupContainer ;
@Override
public void initialize(URL location, ResourceBundle resources) {
final ImageView imageView = new ImageView("com/ong/Images/not_logo.png");
final Circle clip = new Circle(300, 200, 200);
imageView.setClip(clip);
groupContainer = new HBox();
groupContainer.getChildren().add(imageView);
groupsMenuScrollPane.setContent(groupContainer);
// this is not needed since it's already done in FXML:
// borderPane.setTop(groupsMenuScrollPane);
// ...
}
public void addGroup(...) {
// not sure exactly what you want to add, but for example,
// to add a new image view you would do:
ImageView imageView = new ImageView(...);
groupContainer.getChildren().add(imageView);
}
}
加载 FXML 时,保留对控制器的引用:
FXMLLoader loader = new FXMLLoader(getClass().getResource(...));
Parent root = loader.load();
HomepageController controller = loader.getController();
然后您可以使用
向滚动窗格添加内容controller.addGroup(...);
如另一个答案中所述,ListView
可能是更好的方法。
您可能还应该考虑 MVC 方法(例如,参见 ObservableList<...>
来存储组列表。控制器可以观察该列表并在它更改时修改滚动窗格的内容。然后你所要做的就是通过模型向列表中添加一些东西。