簡體   English   中英

Javafx from a thread notify events to controller class for setting Label,Textfield based on model

[英]Javafx from a thread notify events to controller class for setting Label,Textfield based on model

在線程中我運行一些代碼,我需要更新 JsonOverviewController 中的 javafx ui 元素。 我不想在 model 或 class controller 中傳遞 ui 元素。 我不想要這個

        jfWatch = new WatchController();
        jfWatch.setPathDirectory(absPathSelDir);
        jfWatch.setMyJsonFilesTable(myJsonFilesTable);
        jfWatch.setMyIdTableColumn(myIdTableColumn);
        ...
        
        jfWatch.setMyStateLabel(myStateLabel);
        
        jfWatch.start();

下面的代碼顯示 Label.TextField 被傳遞給線程並在運行方法中更新它們。

package it.einaudi.storejson;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;

import com.fasterxml.jackson.core.JsonParseException;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import it.einaudi.storejson.model.ConnectionConfig;
import it.einaudi.storejson.model.JsonFile;
import it.einaudi.storejson.model.JsonFileManager;

public class JsonOverviewController {
    
    @FXML
    private Button myButton;
    
    @FXML
    private Label myDirWatch;
    
    @FXML
    private Label myCurrentJsonFileId;
    
    @FXML
    private Label myCurrentJsonFileName;
    
    @FXML
    private TextArea myCurrentJsonFileContent;
    
    @FXML
    private Button myImportButton;
    
    @FXML
    private TableView<JsonFile> myJsonFilesTable;
    
    @FXML
    private TableColumn<JsonFile, String> myIdTableColumn;
    
    @FXML
    private TableColumn<JsonFile, String> myNameFileTableColumn;
    
    @FXML
    private TableColumn<JsonFile, String> myStateTableColumn;
    
    @FXML
    private TextField myConnFullurlField;
    
    @FXML
    private TextField myConnUsernameField;
    
    @FXML
    private TextField myConnPasswordField;
    
    @FXML
    private TextField myConnNamedbField;
    
    @FXML
    private Label myStateLabel;
    
    //private JsonWatchService threadJsonWatch;
    private WatchController jfWatch;
    
    private JsonFileManager jfManager;
    
    /**
     * The constructor (is called before the initialize()-method).
     */
    public JsonOverviewController() {       
        //threadJsonWatch = null;
        jfManager = null;
        jfWatch = null;
    }
    
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        // Button was clicked, do something...
        System.out.println("myButton premuto");
        DirectoryChooser directoryChooser = new DirectoryChooser();
        Node node = (Node) event.getSource();
        File selectedDirectory;
        Stage thisStage = (Stage) node.getScene().getWindow();
        String absPathSelDir;
        
        selectedDirectory = directoryChooser.showDialog(thisStage);
        if(selectedDirectory == null ) return;
        
        absPathSelDir = selectedDirectory.getAbsolutePath();
        
        myDirWatch.setText(absPathSelDir);
            
        if(jfWatch != null) jfWatch.interrupt();
        
        jfWatch = new WatchController();
        jfWatch.setPathDirectory(absPathSelDir);
        jfWatch.setMyJsonFilesTable(myJsonFilesTable);
        jfWatch.setMyIdTableColumn(myIdTableColumn);
        jfWatch.setMyNameFileTableColumn(myNameFileTableColumn);
        jfWatch.setMyStateTableColumn(myStateTableColumn);
        
        jfWatch.setMyCurrentJsonFileId(myCurrentJsonFileId);
        jfWatch.setMyCurrentJsonFileName(myCurrentJsonFileName);
        jfWatch.setMyCurrentJsonFileContent(myCurrentJsonFileContent);
        
        jfWatch.setMyStateLabel(myStateLabel);
        
        jfWatch.start();
        
        myStateLabel.setText("La cartella " + 
                             absPathSelDir + 
                             " è monitorata.");    
    }
    
    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */
    
    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */
    @FXML
    private void initialize() {
        // Handle Button event.
        myButton.setOnAction(this::handleButtonAction);
        
        myIdTableColumn.setCellValueFactory(new PropertyValueFactory<JsonFile,String>("idFile"));
        myNameFileTableColumn.setCellValueFactory(new PropertyValueFactory<JsonFile,String>("nameFile"));
        myStateTableColumn.setCellValueFactory(new PropertyValueFactory<JsonFile,String>("stateFile"));
        
    }
    
}

public class WatchController extends Thread {
    
    private String pathDirectory;
    
    private Label myCurrentJsonFileId;
    
    private Label myCurrentJsonFileName;
    
    private TextArea myCurrentJsonFileContent; 
    
    private TableView<JsonFile> myJsonFilesTable;
    
    private TableColumn<JsonFile, String> myIdTableColumn;
    
    private TableColumn<JsonFile, String> myNameFileTableColumn;
    
    private TableColumn<JsonFile, String> myStateTableColumn;
    
    private Label myStateLabel;

    public void run() {
        if(!found) {
            Platform.runLater(() -> myCurrentJsonFileId.setText(""));
            Platform.runLater(() -> myCurrentJsonFileName.setText(""));
            Platform.runLater(() -> myCurrentJsonFileContent.setText("Anteprima file json non disponibile."));  
        }else {
            final JsonFile firstJCopy = firstJ;
            Platform.runLater(() -> myCurrentJsonFileId.setText(firstJCopy.getIdFile()));
            Platform.runLater(() -> myCurrentJsonFileName.setText(firstJCopy.getNameFile()));
            
            fullPathFile = pathDirectory + "\\" + firstJ.getNameFile();
            System.out.println(fullPathFile);
            strJ = readFileAsList(fullPathFile);
            String strJCopy = strJ;
            Platform.runLater(() -> myCurrentJsonFileContent.setText(strJCopy));
        }
    }
}

相反,我希望我的線程通知已發生的 controller 並將 model 的一些數據發送到 controller。 因此在 controller class 基於數據 model 正確設置 ZB021DF6AAC4654C454F46C77646E,

在標准 MVC 架構中,您的 model 應該包含一個監聽器列表,並且應該根據需要通知這些監聽器事件。 您的 controller(在 JavaFX 中使用 FXML 更像是 MVP 演示者)應該是一個監聽器,並且應該使用 model 注冊自己。

所以:

public interface WatchListener {
    public void startedProcessing();
    public void fileProcessed(String data);
    public void notFound();
}
public class WatchController extends Thread {
    
    private String pathDirectory;
    
    private final List<WatchListener> listeners = new ArrayList<>();

    public void addListener(WatchListener listener) {
        listeners.add(listener);
    }

    public void removeListener(WatchListener listener) {
        listeners.remove(listener);
    }

    public void run() {
        if(!found) {
            Platform.runLater(() -> {
                listeners.forEach(WatchListener::notFound);
            }); 
        } else {
            final JsonFile firstJCopy = firstJ;
            Platform.runLater(() -> {
                listeners.forEach(WatchListener::startedProcessing);
            });
            
            fullPathFile = pathDirectory + "\\" + firstJ.getNameFile();
            System.out.println(fullPathFile);
            strJ = readFileAsList(fullPathFile);
            String strJCopy = strJ;
            Platform.runLater(() -> {
                listeners.forEach(listener -> listener.fileProcessed(strJCopy));
            });
        }
    }
}

然后在您的 controller 中:

public class JsonOverviewController implements WatchListener {
    
    // fields and initialize method as before
    
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        // Button was clicked, do something...
        System.out.println("myButton premuto");
        DirectoryChooser directoryChooser = new DirectoryChooser();
        Node node = (Node) event.getSource();
        File selectedDirectory;
        Stage thisStage = (Stage) node.getScene().getWindow();
        String absPathSelDir;
        
        selectedDirectory = directoryChooser.showDialog(thisStage);
        if(selectedDirectory == null ) return;
        
        absPathSelDir = selectedDirectory.getAbsolutePath();
        
        myDirWatch.setText(absPathSelDir);
            
        if(jfWatch != null) jfWatch.interrupt();
        
        jfWatch = new WatchController();
        watchController.addListener(this);
        jfWatch.setPathDirectory(absPathSelDir);
        
        jfWatch.start();
        
        myStateLabel.setText("La cartella " + 
                             absPathSelDir + 
                             " è monitorata.");    
    }
    
    @Override
    public void startedProcessing() {
        myCurrentJsonFileId.setText("");
        myCurrentJsonFileName.setText("");
        myCurrentJsonFileContent.setText("Anteprima file json non disponibile.");
    }

    @Override
    public void fileProcessed(String data) {
        myCurrentJsonFileContent.setText(data);
    }

    @Override
    public void notFound() {
        myCurrentJsonFileId.setText("");
        myCurrentJsonFileName.setText("");
        myCurrentJsonFileContent.setText("Anteprima file json non disponibile.");  
    }
}

比在這里使用普通線程更好的方法可能是使用 JavaFX 並發 API 並將WatchController實現為Task 這支持在 FX 應用程序線程上執行任務何時啟動、完成等的代碼(它基本上會在 state 更改時為您處理所有Platform.runLater()調用)。 這看起來像:

public class WatchController extends Task<String> {

    private final String pathDirectory;

    public WatchController(String pathDirectory) {
        this.pathDirectory = pathDirectory ;
    }

    @Override
    public String call() throws Exception {
        if(!found) {
            throw new FileNotFoundException(pathDirectory + " not found");
        } else {
            final JsonFile firstJCopy = firstJ;
            fullPathFile = pathDirectory + "\\" + firstJ.getNameFile();
            System.out.println(fullPathFile);
            return readFileAsList(fullPathFile);
        }
    }
}

然后在 controller 中:

public class JsonOverviewController implements WatchListener {

    // fields and initialize method as before

    private final Executor exec = Executors.newCachedThreadPool();


    @FXML
    private void handleButtonAction(ActionEvent event) {
        // Button was clicked, do something...
        System.out.println("myButton premuto");
        DirectoryChooser directoryChooser = new DirectoryChooser();

        File selectedDirectory = directoryChooser.showDialog(myButton.getScene().getWindow());
        if(selectedDirectory == null ) return;

        String absPathSelDir = selectedDirectory.getAbsolutePath();

        myDirWatch.setText(absPathSelDir);

        if(jfWatch != null) jfWatch.cancel();

        jfWatch = new WatchController(absPathSelDir);
        watchController.setOnRunning(evt -> startedProcessing());
        watchController.setOnFailed(evt -> notFound());
        watchController.setOnSucceeded(evt -> fileProcessed(jfWatch.getValue());

        exec.execute(jfWatch);

        myStateLabel.setText("La cartella " + 
                             absPathSelDir + 
                             " è monitorata.");    
    }

    @Override
    public void startedProcessing() {
        myCurrentJsonFileId.setText("");
        myCurrentJsonFileName.setText("");
        myCurrentJsonFileContent.setText("Anteprima file json non disponibile.");
    }

    @Override
    public void fileProcessed(String data) {
        myCurrentJsonFileContent.setText(data);
    }

    @Override
    public void notFound() {
        myCurrentJsonFileId.setText("");
        myCurrentJsonFileName.setText("");
        myCurrentJsonFileContent.setText("Anteprima file json non disponibile.");  
    }
}

您可能需要在Task實現中做更多的工作,以完全支持以適當的方式取消任務。 有關更多詳細信息,請參閱Task文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM