从TableView中删除选定的行,并在JavaFX中有效使用SceneBuilder

时间:2016-03-17 16:15:50

标签: java javafx

我试图创建一个应用程序,从文件中的文本创建一个表,然后用户可以添加或删除单词。文本文件用于我的应用程序中填充下拉框的位置,以便用户只能在下拉框中选择文本。

我的问题是我无法从表中删除只添加它,我可以在网上找到的任何内容都是由类创建的表。我的表只是一个非常基本的表,有一列字符串。出于某种原因,当我打印表格的选定项目时,我总是得不到任何东西?我无法弄清楚原因。

我几周前才开始使用javaFx我真的只是从视频和书籍中学习,但与我预期的应用相比,它们非常简单。

这是我的代码:

public class MaintenWindow {

private static Stage window;
private static TableView<String> table = new TableView<String>();
private static TextField input;
private static ObservableList<String> stringList;
private static BorderPane bP;
private static Scene scene;

private static File types = new File("type.txt");
private static File location = new File("location.txt");
private static File status = new File("status.txt");

public static void display() throws FileNotFoundException  {
    window = new Stage();
    BorderPane bP = new BorderPane();

    window.setTitle("Mainten Window");

    MenuBar menuBar = new MenuBar();

    Menu fileMenu = new Menu("_Add/Remove From DropDowns");
    MenuItem editLocation = new MenuItem("_Edit Locations");
    MenuItem editAtypes = new MenuItem("_Edit Animal Types");
    MenuItem editStatus = new MenuItem("_Edit Status's");
    MenuItem exit = new MenuItem("Exit");
    fileMenu.getItems().addAll(editLocation, editAtypes, editStatus, new SeparatorMenuItem(),exit);

    menuBar.getMenus().addAll(fileMenu);
    editLocation.setOnAction(e -> {
        bP.setTop(menuBar);
        bP.setCenter(vBox("Locations", location));
        window.setScene(scene);
        window.show();              
    });

    editAtypes.setOnAction(e -> {
        bP.setTop(menuBar);
        bP.setCenter(vBox("Animal Types", types));
        window.setScene(scene);
        window.show();              
    });

    editStatus.setOnAction(e -> {
        bP.setTop(menuBar);
        bP.setCenter(vBox("Status", status));
        window.setScene(scene);
        window.show();              
    });


    bP.setTop(menuBar);
    scene = new Scene(bP, 800,800);

    Label label = new Label("welcome to the maintenance window");


    bP.setCenter(label);

    window.setScene(scene);
    window.show();

}

/*public static MenuBar menuBar()
{
    //file tab menu
    Menu fileMenu = new Menu("_Add/Remove From DropDowns");
    MenuItem editLocation = new MenuItem("_Edit Locations");
    MenuItem editAtypes = new MenuItem("_Edit Animal Types");
    MenuItem editStatus = new MenuItem("_Edit Status's");
    MenuItem exit = new MenuItem("Exit");
    fileMenu.getItems().addAll(editLocation, editAtypes, editStatus, new SeparatorMenuItem(),exit);

    editLocation.setOnAction(e -> {
        bP.setTop(menuBar());
        bP.setCenter(vBox("Locations", location));
        window.setScene(scene);
        window.show();              
    });

    editAtypes.setOnAction(e -> {
        bP.setTop(menuBar());
        bP.setCenter(vBox("Animal Types", types));
        window.setScene(scene);
        window.show();              
    });

    editStatus.setOnAction(e -> {
        bP.setTop(menuBar());
        bP.setCenter(vBox("Status", status));
        window.setScene(scene);
        window.show();              
    });

    MenuBar menuBar = new MenuBar();
    menuBar.getMenus().addAll(fileMenu);

    return menuBar;
}*/

public static ObservableList<String> getString(File file) throws FileNotFoundException{
    stringList = FXCollections.observableArrayList();

    Scanner kb = new Scanner(file);
    String item;
    while (kb.hasNext()) {
        item = kb.nextLine();
        stringList.add(item);
    }

    kb.close();
    return stringList;
}

@SuppressWarnings("unchecked")
public static TableView<String> table(String string,File file)
{
    TableColumn<String, String> tColumn = new TableColumn<String, String>(string);
    tColumn.setCellValueFactory(cellData -> 
    new ReadOnlyStringWrapper(cellData.getValue()));
    TableView<String> table = new TableView<String>();
    try {
        table.setItems(getString(file));
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    table.getColumns().addAll(tColumn);

    table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    return table;
}

public static void addButtonClicked(){

    stringList.add(input.getText());
    input.clear();
}

//Delete button clicked
public static void deleteButtonClicked(){
    ObservableList<String> allStrings, stringSelected;
    allStrings = table.getItems();
    //printElements(allStrings);
    System.out.println(table.getSelectionModel().getSelectedItems());

    stringSelected = table.getSelectionModel().getSelectedItems();
    System.out.println(stringSelected);
    stringSelected.forEach(allStrings::remove);
}

public static HBox textFields() {
    input = new TextField();
    input.setPromptText("Input");
    input.setMinWidth(75);

    HBox hBox = new HBox();
    hBox.setPadding(new Insets(10,10,10,10));
    hBox.setSpacing(10);
    hBox.getChildren().addAll(input);

    return hBox;
}

public static HBox addRemove(File file){
    //Button
    Button addButton = new Button("Add");
    addButton.setOnAction(e -> addButtonClicked());
    Button deleteButton = new Button("Delete");
    deleteButton.setOnAction(e -> deleteButtonClicked());
    Button writeButton = new Button("Write to file");
    try {
        try {
            writeButton.setOnAction(e -> write(file));
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    } catch (Exception e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    Button closeButton = new Button("Close Window");
    closeButton.setOnAction(e -> window.close());

    HBox hBox2 = new HBox();
    hBox2.setPadding(new Insets(10,10,10,10));
    hBox2.setSpacing(10);
    hBox2.getChildren().addAll(addButton, deleteButton, writeButton, closeButton);

    return hBox2;
}

private static void printElements(ObservableList<String> list) {
    System.out.println("Size: " + list.size());
    for (Object o : list) {
        System.out.println(o.toString());
    }
    System.out.println("");
}

public static void write(File file)
{
    PrintWriter outFile = null;
    try {
        outFile = new PrintWriter(file);
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    for(int i = 0; i < stringList.size(); i++)
    {
        outFile.println(stringList.get(i));
    }
    outFile.close();
}

public static VBox vBox(String string, File file){
    Label label = new Label(string);
    label.setFont(new Font("Arial", 20));

    VBox vBox = new VBox();
    vBox.setSpacing(5);
    vBox.setPadding(new Insets(10, 0, 0, 10));
    vBox.getChildren().addAll(label, table(string,file), textFields(), addRemove(file));

    return vBox;
}

}

我会很乐意提供任何帮助。 如果您对我有任何提示或建议,请发布 如果您有更多高级javafx程序的链接,请发布它们。

1 个答案:

答案 0 :(得分:1)

出了什么问题

您的代码中存在逻辑错误,您可以在其中创建表的两个实例。你在班上宣布:

private static TableView<String> table = new TableView<String>();

然后在你的table()函数中声明一个新函数的局部表

TableView<String> table = new TableView<String>();
table.setItems(getString());
table.getColumns().addAll(tColumn);

return table;

然后,您最终将table()函数返回的表添加到场景中:

vbox.getChildren().addAll(label, table(), textFields(), addRemove());

但是在你的应用程序的其他地方,例如deleteButtonClicked(),你调用:

table.getSelectionModel().getSelectedItems();

但是这将会影响你的类中声明的实例,而不是你方法中声明的实例,所以它总会返回一个空列表。

如何解决

要解决此问题,只需创建一个新的TableView,而不是两个。

以下是一些简化的示例代码:

import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class MaintenanceWindow extends Application {
    private TableView<String> table;
    private TextField input;
    private Stage myStage;

    private static final String[] ITEMS = { "apples", "oranges", "peaches", "pears" };

    @Override
    public void start(Stage stage) throws Exception {
        myStage = stage;
        final Label label = new Label("list");
        label.setFont(new Font("Arial", 20));

        VBox vbox = new VBox(
                5,
                label, table(), textFields(), addRemove()
        );
        vbox.setPadding(new Insets(10, 0, 0, 10));

        BorderPane bP = new BorderPane();
        bP.setTop(menuBar());
        bP.setCenter(vbox);

        stage.setScene(new Scene(bP, 700, 800));
        stage.show();
    }

    private MenuBar menuBar() {
        Menu fileMenu = new Menu("_Add/Remove From DropDowns");
        MenuItem locationAdd = new MenuItem("Location DropDowns Add");
        locationAdd.setOnAction(e -> addButtonClicked());
        MenuItem locationRemove = new MenuItem("Location DropDowns Remove");
        locationRemove.setOnAction(e -> deleteButtonClicked());
        MenuItem exit = new MenuItem("Exit");
        exit.setOnAction(e -> closeApp());
        fileMenu.getItems().addAll(
                locationAdd,
                new SeparatorMenuItem(),
                locationRemove,
                new SeparatorMenuItem(),
                exit
        );

        MenuBar menuBar = new MenuBar();
        menuBar.getMenus().addAll(fileMenu);
        return menuBar;
    }

    private TableView<String> table() {
        TableColumn<String, String> tColumn = new TableColumn<>("String");
        tColumn.setMinWidth(250);
        tColumn.setCellValueFactory(
                cellData -> new ReadOnlyStringWrapper(cellData.getValue())
        );
        table = new TableView<>();
        table.getItems().addAll(ITEMS);
        table.getColumns().add(tColumn);

        return table;
    }

    private void addButtonClicked() {
        if (!(input.getText() == null || "".equals(input.getText().trim())) {
            table.getItems().add(input.getText());
            input.clear();
        }
    }

    private void deleteButtonClicked() {
        table.getItems().removeAll(
                table.getSelectionModel().getSelectedItems()
        );
    }

    private HBox textFields() {
        input = new TextField();
        input.setPromptText("Input");
        input.setMinWidth(75);

        HBox hBox = new HBox();
        hBox.setPadding(new Insets(10, 10, 10, 10));
        hBox.setSpacing(10);
        hBox.getChildren().addAll(input);

        return hBox;
    }

    private HBox addRemove() {
        Button addButton = new Button("Add");
        addButton.setOnAction(e -> addButtonClicked());
        Button deleteButton = new Button("Delete");
        deleteButton.setOnAction(e -> deleteButtonClicked());
        Button closeButton = new Button("Close Window");
        closeButton.setOnAction(e -> closeApp());

        HBox hBox2 = new HBox(
                10,
                addButton, deleteButton, closeButton
        );
        hBox2.setPadding(new Insets(10, 10, 10, 10));
        hBox2.setSpacing(10);

        return hBox2;
    }

    private void closeApp() {
        myStage.close();
    }
}

image

对未来问题的无关建议:

那些不寻求建议的人可以跳过阅读本答复的其余部分,因为它并不直接适用于这个问题。

  • 创建mcve
  • 按照debugging small programs的步骤操作。如果您有一个大型计划并且无法解决正在发生的事情,那么只需创建一个小程序。
  • 随着程序变大,要么从一开始就设计多个类,要么重构它以使用多个类。
  • 使用FXMLSceneBuilder复杂的布局,而不是手工编码。
  • 浏览makery JavaFX tutorial并仔细研究(看起来与您在此处尝试的非常相似)。
  • 只需在StackOverflow上针对每个问题提出一个问题,并将解决每个问题的代码隔离到仅解决该问题的特定mcve。例如关于文件例外的原始附加问题(看起来有人现在已经编辑出你的问题),只是将其作为一个单独的问题发布。
  • 如果您的程序有效(但不是太大),请将其代码发布到codereview,以获取有关通用编程技术,约定和设计方法的反馈(例如,它们肯定会给您反馈而不使用静态方法无处不在)。有关您应该发布到代码审核的各种事物的示例以及您可以预期的反馈类型,请参阅An alarm application in Java(FX)的编码查看。
  • Stackoverflow不是一个真正的提示和建议网站,它只是纯粹的Q&amp; A.
  

你会为新手javafx程序员推荐使用scenebuilder吗?

是。我曾经不是不为初学者推荐它,但是已经开始认为使用该工具进行初始实验和以后的开发是一个好主意,即使对于新手JavaFX程序员也是如此。使用SceneBuilder工具而不是直接针对Java API进行编程,新开发人员可以更轻松,更高效地深入了解布局如何工作以及在节点,区域和各种控件上公开哪些属性。

但是,单独学习SceneBuilder和FXML并不能替代实际学习如何针对Java API进行编程,而您需要编写代码。所以一定要做好这两件事,在SceneBuilder 中针对Java API编写代码。首先,通过在场景构建器中探索JavaFX控件和布局并查看它生成的FXML,并编写仅针对Java API编写的小型独立程序,而不使用FXML,将这些事物分开。然后,只有在你对这两件事情相对满意的情况下,才能解决之前链接的Makery教程中的项目,它结合了Scene Builder来定义基于FXML的UI以及在中等大小的应用程序中使用这些FXML文件,其中包括针对Java API的代码。

此外,既不使用SceneBuilder也不玩API,可以替代working through the JavaFX tutorialsunderstanding layout fundamentals such as Groups, layout panes and Regions,必须这样做才能合理掌握技术。

没有JavaFX程序可以单独依赖FXML,如果使用FXML,则需要FXML和Java代码的组合才能获得有效的程序。任何使用大量控件和布局的重要JavaFX程序最好使用FXML布局,样式的CSS和逻辑的Java(或其他语言)代码进行编码。因此,最终您需要学习所有三种技术(FXML,CSS和JavaFX API)以及如何使它们一起运行,以便超越琐碎的程序。

我看到新的JavaFX开发人员遇到的SceneBuilder的一个问题是在SceneBuilder中创建一个复杂的UI相对简单,但对于新手来说,采用复杂的UI并为其添加正确的逻辑是相对困难的。应用程序实际上应该是功能的。因此,在了解如何使用JavaFX Java API以及如何使用JavaFX Java为一些非常基本的FXML文件添加逻辑之前,不要错误地在SceneBuilder中为应用程序定义完整的UI。 API。

此外,一旦开始编写多个FXML文件,每个人遇到的问题都是:

  

我选择不使用它,因为我觉得它看起来很复杂,因为你需要一个xml和控制器

是的,它(相对而言),理解起来更复杂,并且您必须拥有更多技能来初始创建基于FXML / CSS的应用程序而不是针对纯Java API编写的内容。但是,一旦你构建了一个,我猜你会发现一个基于中间大小的FXML / CSS的应用程序比纯粹针对Java API编写的等效应用程序更容易理解和维护。