尝试从文件读取时 JavaFX 构建崩溃

问题描述 投票:0回答:1

我正在做期中考试,我们必须制作一个 GUI 购物清单。教授要求我们将列表放入 .txt 文件并从该文件中读取。还有一个删除部分,删除所有我还没有编码的部分。通常,每当我向其中添加新内容时,我都会测试代码。当尝试测试这个时,我注意到它崩溃了。该代码正在写入 Grocery.txt,但未显示写入列表框中的内容。我知道我很可能错过了一些小事。当我查看我的教科书“Murach 的 Java 编程第六版”时,它看起来几乎相同,只是他们使用的示例是从文件中读取三个不同的内容。他们正在使用数组来读取。我试图将每一个都放在自己的线上。我知道现在不会。我正在尝试测试它是否能够读取它,但目前还没有。

更新:我现在更改了一些代码,当我单击“添加”时,我收到一个显示错误的空警报框。已放置更新的代码。我会离开几个小时,然后回来继续工作。谢谢大家的帮助。

这是我当前的代码:

package com.mycompany.zaph_midterm;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;



public class App extends Application {
    public TextField addGrocery;
    public ListView<String> groceryList = new ListView<>();
    @Override
    public void start(Stage stage) {
        stage.setTitle("Grocery List");
        
        //Setting grid
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setPadding(new Insets(15,15,15,15));
        grid.setHgap(10);
        grid.setVgap(10);
        
        //attaching grid to scene
        Scene scene = new Scene(grid);
        
        //Setting the add section
        HBox hbox = new HBox();
        GridPane addHbox = new GridPane();
        addHbox.add(new Label ("Items: "), 0, 0);
        addHbox.add(new Label("  "), 1, 0);
        addGrocery = new TextField();
        addHbox.add(addGrocery, 2, 0);
        Button addButton = new Button("Add");
        addButton.setOnAction(event -> addButtonClicked());
        addHbox.add(new Label("  "), 3, 0);
        addHbox.add(addButton, 4, 0);
        hbox.getChildren().add(addHbox);
        grid.add(hbox, 0, 0);
        
        //Setting list to show
        HBox groceryBox = new HBox();
        GridPane groceryGrid = new GridPane();
        groceryGrid.add(new Label("List: "), 0, 0);
        groceryList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
groceryList.getItems().add(grocery.readFromFile(addGrocery.getText()));
        groceryGrid.add(groceryList, 2, 0);
        groceryBox.getChildren().add(groceryGrid);
        grid.add(groceryBox, 0, 1);
        
        stage.setScene(scene);
        stage.show();
    }
    // Add button clicked 
    private void addButtonClicked() {
        //Validation of user Input
        Validation v = new Validation();
        String errorMsg = "";
        errorMsg += v.hasValue(addGrocery.getText());
        errorMsg += v.isBlank(addGrocery.getText());
        
        // Using if/else to add to grocery List
        if (errorMsg == ""){
            GroceryList grocery = new GroceryList();
            //Adding to Grocery List
            grocery.printToFile(addGrocery.getText());
             
           
        }else {
           Alert wrong = new Alert(Alert.AlertType.ERROR);
           wrong.setHeaderText("Error");
           wrong.setContentText(errorMsg);
           wrong.showAndWait();
        }
    }
    
    public static void main(String[] args) {
        launch();
    }

验证类:

package com.mycompany.zaph_midterm;


public class Validation {
    private final String lineEnd;
    
   public Validation() {
       this.lineEnd = "\n";
   } 
   
   public Validation(String lineEnd) {
       this.lineEnd = lineEnd;
   }
   
   public String isBlank(String name) {
       String error = "";
       if(name.isBlank()) {
           error = "Must have groceries in the add text box.";
       }
       return error;
   }// end of isBlank
   
   public String hasValue(String name) {
       //if user input is able to be parsed then an error message will return
       String error = "";
       try {
           Double.parseDouble(name);
       } catch (NumberFormatException e) {
           return error;
       }
       error ="Text box must only contain letters";
       return error;
   }
}

杂货清单类:

package com.mycompany.zaph_midterm;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import static java.lang.System.out;


public class GroceryList {
    private String grocery;
    
    
    public GroceryList() {
        grocery = " ";
        
    }
    
    public void setGroceryList(String args){
        this.grocery = grocery;
        
    }
    public String getGroceryList() {
        return grocery;
    }
    
    public void printToFile(String grocery) {
        //creating file
        try (PrintWriter out = new PrintWriter(
                               new BufferedWriter(
                               new FileWriter("Grocery.txt")))) {
            //writing to file
            out.print(grocery);
            
        }
        //catching error if found
        catch (IOException e){
          System.out.println(e);
        }
    }
    public void deleteFromFile(String grocery) {
        
    }
    public String readFromFile(String grocery) throws IOException{
        try (BufferedReader in = new BufferedReader(
                                 new FileReader("Grocery.txt"))){
            String line = in.readLine();
            while (line != null){
               line = grocery;
               return grocery;
            }
            
        }
        catch (IOException e) {
            Alert error = new Alert(Alert.AlertType.ERROR);
            error.setHeaderText("Didn't work");
            error.setContentText("Something is wrong");
            error.showAndWait();
        }
        return grocery;
    }
        
    }
    
}


我尝试将 try(BufferedReader) 移动到 addButtonCLicked() 仍然崩溃,所以我将它移到 //setting 列表下显示,但它仍然崩溃。

java javafx crash bufferedreader filereader
1个回答
0
投票

您的问题没有重点、不清楚。但是,为了好玩,我会尝试修改您的代码。

编程中的一个非常有用的概念是“关注点分离”。这意味着将您的代码组织成单独的块,每个块专注于特定的工作。 其中一项工作是将购物清单中的项目写入存储,然后将其读回。那应该是在一个特定的班级中。我们将这个类称为

Repository

我们需要定义要进入存储库的对象。您的 

GroceryList

类考虑不周,因为列表只是项目的集合。这是我们需要定义的项目。我们可以简单地通过

记录
来做到这一点。该类唯一的工作是表示代表现实世界中的杂货商品所需的验证状态。 public record GroceryItem( String name ) { public GroceryItem ( final String name ) { Objects.requireNonNull ( name ); if ( name.isBlank ( ) ) throw new IllegalArgumentException ( "Grocery item name cannot be blank." ); this.name = name; } }

存储库需要保存杂货并再次检索。这个类唯一的工作就是持久存储和检索对象的状态。在这里,我们编写了一个简单的伪造实现,足以开始使用。

public class Repository { private List < GroceryItem > storedGroceryItems = new ArrayList <> ( List.of ( new GroceryItem ( "Bananas" ) , new GroceryItem ( "Eggs" ) , new GroceryItem ( "Olive oil" ) ) ); public List < GroceryItem > fetchGroceryItems ( ) { return List.copyOf ( this.storedGroceryItems ); } public boolean saveGroceryItem ( final GroceryItem groceryItem ) { if ( this.storedGroceryItems.contains ( groceryItem ) ) return false; return this.storedGroceryItems.add ( groceryItem ); } public boolean deleteGroceryItem ( final GroceryItem groceryItem ) { return this.storedGroceryItems.remove ( groceryItem ); } public boolean removeAllGroceryItems ( ) { List < GroceryItem > emptyList = List.of ( ); return this.storedGroceryItems.retainAll ( emptyList ); } }

编写一些快速测试来验证。

public class TestRepository { public static void main ( String[] args ) { TestRepository.testPreloadedRepository ( ); } public static void testPreloadedRepository ( ) { Repository repository = new Repository ( ); boolean success; List < GroceryItem > list = repository.fetchGroceryItems ( ); System.out.println ( "list has 3 elements: " + ( list.size ( ) == 3 ) ); List < GroceryItem > expectedList = List.of ( new GroceryItem ( "Bananas" ) , new GroceryItem ( "Eggs" ) , new GroceryItem ( "Olive oil" ) ); System.out.println ( "list has expected items: " + ( list.equals ( expectedList ) ) ); GroceryItem broccoli = new GroceryItem ( "Broccoli" ); success = repository.saveGroceryItem ( broccoli ); System.out.println ( "success = " + success ); list = repository.fetchGroceryItems ( ); System.out.println ( "list has 4 elements: " + ( list.size ( ) == 4 ) ); expectedList = List.of ( new GroceryItem ( "Bananas" ) , new GroceryItem ( "Eggs" ) , new GroceryItem ( "Olive oil" ) , broccoli ); System.out.println ( "list has expected items: " + ( list.equals ( expectedList ) ) ); GroceryItem eggs = new GroceryItem ( "Eggs" ); success = repository.deleteGroceryItem ( eggs ); System.out.println ( "success = " + success ); list = repository.fetchGroceryItems ( ); System.out.println ( "list has 3 elements: " + ( list.size ( ) == 3 ) ); expectedList = List.of ( new GroceryItem ( "Bananas" ) , new GroceryItem ( "Olive oil" ) , broccoli ); System.out.println ( "list has expected items: " + ( list.equals ( expectedList ) ) ); } }

list has 3 elements: true
list has expected items: true
success = true
list has 4 elements: true
list has expected items: true
success = true
list has 3 elements: true
list has expected items: true
现在在 JavaFX 中构建初始 GUI。

public class HelloApplication extends Application { private Repository repository = new Repository ( ); @Override public void start ( Stage stage ) throws IOException { Pane pane = this.buildPane (); Scene scene = new Scene ( pane , 500 , 350 ); stage.setTitle ( "Grocery List" ); stage.setScene ( scene ); stage.show ( ); } private Pane buildPane () { // Data List < GroceryItem > groceryItems = this.repository.fetchGroceryItems ( ); ObservableList < GroceryItem > observableList = FXCollections.observableArrayList ( groceryItems ); // Widgets ListView < GroceryItem > listView = new ListView <> ( observableList ); TextField newGroceryItemField = new TextField ( ); newGroceryItemField.setPromptText ( "new grocery item" ); Button addButton = new Button ( "Add…" ); Button removeButton = new Button ( "Delete" ); // Behavior addButton.setOnMouseClicked ( ( MouseEvent mouseEvent ) -> { String input = newGroceryItemField.getText ( ); if ( input.isBlank ( ) ) return; GroceryItem groceryItem = new GroceryItem ( input ); if ( observableList.contains ( groceryItem ) ) return; if ( this.repository.saveGroceryItem ( groceryItem ) ) { observableList.add ( groceryItem ); } } ); removeButton.setOnMouseClicked ( ( MouseEvent mouseEvent ) -> { GroceryItem groceryItem = listView.getSelectionModel ( ).getSelectedItem ( ); if ( Objects.nonNull ( groceryItem ) ) { if ( this.repository.deleteGroceryItem ( groceryItem ) ) { observableList.remove ( groceryItem ); } } } ); // Arrange BorderPane borderPane = new BorderPane ( ); borderPane.setCenter ( listView ); borderPane.setBottom ( new HBox ( newGroceryItemField , addButton , removeButton ) ); return borderPane; } public static void main ( String[] args ) { launch ( ); } }

所有工作完成后,我们可以回到我们的

Repository

。我们可以重写以实际保存到文件中,而不是使用内存中的虚拟列表。

package work.basil.example.exgrocerylist;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;

public class Repository
{
    private Path dataFilePath = Paths.get ( "/Users/basil_dot_work/GroceryItems.txt" );

    public List < GroceryItem > fetchGroceryItems ( )
    {
        boolean go = this.createAndPopulateFileIfNotExists ( );
        try
        {
            List < String > lines = Files.readAllLines ( this.dataFilePath , StandardCharsets.UTF_8 );
            List < GroceryItem > groceryItems = new ArrayList <> ( );
            for ( String line : lines )
            {
                if ( line.isBlank ( ) )
                {
                    continue;
                }
                GroceryItem groceryItem = new GroceryItem ( line );
                groceryItems.add ( groceryItem );
            }
            return List.copyOf ( groceryItems );
        }
        catch ( IOException e )
        {
            throw new RuntimeException ( e );
        }
    }

    private boolean createAndPopulateFileIfNotExists ( )
    {
        if ( Files.exists ( this.dataFilePath ) ) return true;
        List < GroceryItem > defaultGroceryItems =
                List.of (
                        new GroceryItem ( "Bananas" ) ,
                        new GroceryItem ( "Eggs" ) ,
                        new GroceryItem ( "Olive oil" )
                );
        List < String > lines =
                defaultGroceryItems.stream ( ).map ( GroceryItem :: name ).toList ( );
        try
        {
            Files.write ( this.dataFilePath , lines , StandardCharsets.UTF_8 );
            return ( this.fetchGroceryItems ( ).equals ( defaultGroceryItems ) );
        }
        catch ( IOException e )
        {
            throw new RuntimeException ( e );
        }
    }

    public boolean saveGroceryItem ( final GroceryItem groceryItem )
    {
        List < GroceryItem > groceryItems = this.fetchGroceryItems ( );
        if ( groceryItems.contains ( groceryItem ) ) return false;
        try
        {
            Files.write ( this.dataFilePath , groceryItem.name ( ).getBytes ( ) , StandardOpenOption.APPEND );
        }
        catch ( IOException e )
        {
            throw new RuntimeException ( e );
        }
        return this.fetchGroceryItems ( ).contains ( groceryItem );
    }

    public boolean deleteGroceryItem ( final GroceryItem groceryItem )
    {
        List < GroceryItem > groceryItems = this.fetchGroceryItems ( );
        if ( ! groceryItems.contains ( groceryItem ) ) return false;
        List < GroceryItem > groceryItemsModifiable = new ArrayList <> ( groceryItems );
        boolean go = groceryItemsModifiable.remove ( groceryItem );
        if ( ! go )
        {
            return false;
        }
        List < String > lines = groceryItemsModifiable.stream ( ).map ( GroceryItem :: name ).toList ( );
        try
        {
            Files.write ( this.dataFilePath , lines , StandardCharsets.UTF_8 );
            return true;
        }
        catch ( IOException e )
        {
            throw new RuntimeException ( e );
        }
    }

    public boolean removeAllGroceryItems ( )
    {
        List < String > lines = List.of ( );
        try
        {
            Files.write ( this.dataFilePath , lines , StandardCharsets.UTF_8 );
            return ( this.fetchGroceryItems ( ).isEmpty ( ) );
        }
        catch ( IOException e )
        {
            throw new RuntimeException ( e );
        }
    }
}

给高级学生的提示:
Repository

应该是一个接口,有两个具体实现:一个用于我们的内存列表,另一个用于我们的文件存储。

注意:这个基于文件的

Repository

有一个错误:用户无法添加多个杂货商品。我们可以确定错误存在于这个基于文件的

Repository
实现中,因为我们可以切换回基于内存列表的实现来查看错误消失。我将保留未发现的错误,因为我已经为作业完成了太多工作。
    

© www.soinside.com 2019 - 2024. All rights reserved.