java - 动态 Javafx 视图的控制器类
问题描述
我是Javafx和Spring的新手,我制作了一个简单的桌面应用程序来从数据库加载数据并将其显示在tableview中。我已将所有代码放在一个类中,该类创建视图并加载表并处理添加新行和编辑表。但我很困惑如何将此类拆分为Controller和View部分(如 MVC 模式)。我的课看起来像这样:
package com.waq;
// some imports
@Component
public class PartsView{
private TableView table;
TextField desc;
Label title;
Button save;
GridPane grid;
@Autowired
private PartService partService;
public PartsView(){
createTable();
grid = new GridPane();
save = new Button();
save.setText("Save");
save.setOnAction((ActionEvent e) -> {
// Some logic
}
}
private void loadData() {
List<Part> parts = partService.findAll();
if(parts.size() > 0) {
ObservableList<Part> observableArrayList = FXCollections.observableArrayList(parts);
table.setItems( observableArrayList);
}
else
table.setPlaceholder(new Label("No data to show."));
}
private void saveData(){
// save record.
}
private void createTable(){
CustomTableColumn<Part,String> idColumn = new CustomTableColumn<Part,String>("id");
idColumn.setPercentWidth(10);
idColumn.setCellValueFactory(new PropertyValueFactory<Part,String>("id"));
CustomTableColumn<Part,String> descCol = new CustomTableColumn<Part,String>("description");
descCol.setPercentWidth(50);
descCol.setCellValueFactory(new PropertyValueFactory<Part,String>("description"));
table.getColumns().addAll(idColumn,descCol);
grid.getChildren().add(table);
}
}
我看到了其他示例,但大多数是在fxml文件中生成视图,然后使用@FXML注释获取视图对象。但在我的例子中,我在类中创建视图对象。如果我在视图和控制器类中分离这个类,那么我将如何定义操作让我们说保存按钮以及我将如何在控制器类中访问我的表格视图?
任何帮助将不胜感激。
解决方案
如果您将自定义 JavaFx 创建Node
为Bean
,则可以@Autowired
将其添加到控制器,但您必须添加一个Node
代表您的自定义Node
.
你有两种方法:
extends
你的阶级Node
(或继承人Node
)(看例子)root-Node
从包含其他节点的类返回
例子:
@Component
@Scope("prototype") //If you want to reuse component `@Scope("prototype")`
public class PartsView extends GridPane{
...
public void init(){
getChildren().add(table);
}
}
控制器应如下所示:
public class TestController implements Initializable {
@FXML //StackPane as example
private StackPane stackPane; //injecting before constructor, when you load .fxml
@Autowired
private PartsView partsView; //injecting when you load spring-context
@Override
public void initialize(URL location, ResourceBundle resources) {
// initialize fields marked @FXML annotation.
// method initialize triggering after constructor
}
}
鬃毛问题是您必须Node
在初始化之前将自定义添加到上下文中Controller
。你可以写Configuration
来解决它:
@Configuration
@ComponentScan({
"you.node.packege",
})
public class TestConfig{
@Lazy //depends on your case
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE) //depends on your case
public ControlFx<TabPane, PlanningController> testViewFx() throws IOException {
return loadView("/view/TestLayout.fxml");
}
private <V extends Node, C extends Initializable> ControlFx<V,C> loadView(String url) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(url));
return new ViewFx<>(loader.load(), loader.getController());
}
}
ControlFx 类:
public class ControlFx<N extends Node ,C extends Initializable> {
private final N view;
private final C controller;
public ControlFx(N view, C controller) {
this.view = view;
this.controller = controller;
}
public N getView() {
return view;
}
public C getController() {
return controller;
}
}
我将这个类分为视图类和控制器类,然后我将如何定义保存按钮的操作以及如何在控制器类中访问我的表格视图?
您可以将facade
-method 写入自定义类:
public void setOnActionSaveButton(EventHandler<ActionEvent> value){
save.setOnAction((ActionEvent e) -> {
// Some logic
}
}
我正在使用代码生成所有视图,没有任何 fxml 文件。在那种情况下它将如何工作?
将@Controller
注解(的扩展@Component
)与@PostConstruct
注解一起使用或@Autowired
与构造函数一起使用(或任何init
方式):
@Controller
public class TestController {
private StackPane stackPane;
// @Autowired
private PartsView partsView;
@Autowired
public TestController (PartsView partsView){
...
stackPane.getChildren().add(partsView)
}
// @PostConstruct
// private void beanPostConstruct() {
// stackPane.getChildren().add(partsView);
// }
}
在您的第二个和第三个代码片段中,您提到了加载 fxml 文件,但我没有。
您首先必须初始化 spring-context 。我用过AnnotationConfigApplicationContext
:
public abstract class AbstractJavaFxApplication extends Application {
private static String[] savedArgs;
protected AnnotationConfigApplicationContext context;
@Override
public void init() {
context = new AnnotationConfigApplicationContext(configurations());
context.getAutowireCapableBeanFactory().autowireBean(this);
}
@Override
public void stop() throws Exception {
super.stop();
context.close();
}
protected static void launchApp(Class<? extends AbstractJavaFxApplication> clazz, String[] args) {
AbstractJavaFxApplication.savedArgs = args;
Application.launch(clazz, savedArgs);
}
protected abstract Class<?>[] configurations();
}
实施:
public class ReportApp extends AbstractJavaFxApplication {
public final double PRIMARY_WINDOW_HEIGHT = 500;
public final double PRIMARY_WINDOW_WIDTH = 500;
@Value("${ui.title:JavaFX приложение}")
private String windowTitle;
@Autowired
private RootLayoutController controller;
@Override
public void start(Stage stage) throws Exception {
stage.setTitle(windowTitle);
stage.setScene(
new Scene(
controller.getPane(),
PRIMARY_WINDOW_WIDTH,
PRIMARY_WINDOW_HEIGHT
)
);
stage.setResizable(true);
stage.centerOnScreen();
stage.show();
}
public static void main(String[] args) {
launchApp(ReportApp.class, args);
}
@Override
protected Class<?>[] configurations() {
return new Class<?>[]{
Config.class
};
}
}
配置:
@Configuration
@ComponentScan({"components", "controllers"})
public class Config {
@Bean
...
}
控制器:
@Controller
public class RootLayoutController {
private StackPane stackPane;
@Autowired
private PartsView partsView;
@PostConstruct
private void init(){
stackPane = new StackPane();
stackPane.getChildren().add(partsView);
}
public Pane getPane(){
return stackPane;
}
}
推荐阅读
- php - 使用 Multi-cURL 的正确示例是什么?
- c++ - 链表 C++ 中的最长回文
- python - Pymunk/Chipmunk2d - 动态物体与静态物体碰撞产生碰撞脉冲
- python-3.x - 快速迭代写入 hdf5 文件
- flutter - 使用 FCM Data 包刷新 Flutter 屏幕
- html - 有什么办法可以在垂直菜单中制作一行超文本?
- powershell - 如何使用 PowerShell 在远程计算机上安装 Windows 更新
- java - 搜索适配器onbind方法中的IndexOutofBounexception?
- c# - 在 asp.net core 3.0 中使用 CRM 2011 REST 数据
- c# - 将数据从 CSVReader 传递到循环内的方法