不通过操作其中一个元素来更新JavaFX UI

时间:2019-06-11 02:16:16

标签: user-interface javafx

我正在尝试构建一个具有JavaFX GUI的应用程序,并且该GUI应该通过触发器进行更新,而触发器是Amazon kinesis消费者收到的新记录。 因此,我开始进行一些尝试,并尝试在获得新唱片时用自己选择的颜色(金色)填充一个圆圈,但令GUI惊讶的是没有更新 正确地。甚至在我尝试使用Platform.runlater来运行它之后,如此处所建议的一些问题。 当我调试代码时,令我惊讶的是,我还发现FXML的值 fill属性确实发生了变化,但是它发生在我的断点之前 在函数句柄上,应该进行更改(本身很奇怪)。 但是由于某些原因,我的GUI仍然拒绝更新。

如果我创建一些按钮并使用它触发整个过程,它的确会改变 圆圈的颜色。

我们将不胜感激。

这是我的流程记录功能(monitoringLogic.updateUI更新UI):

public void processRecords(List<Record> records, IRecordProcessorCheckpointer checkpointer) {
    long timestamp = 0;
    List<Long> seqNos = new ArrayList<>();

    for (Record r : records) {

        timestamp = Math.max(timestamp, Long.parseLong(r.getPartitionKey()));

        try {
            byte[] b = new byte[r.getData().remaining()];
            r.getData().get(b);
            seqNos.add(Long.parseLong(new String(b, "UTF-8").split("#")[0]));
            //this thread adds the transaction to the DB
            Thread addTransactionToDBThread = new Thread() {
                public void run() {
                    try {
                        JSONObject jsonObj = new JSONObject(new String(b, "UTF-8").split("#")[1]);
                        Transaction transaction = Transaction.convertJsonToTransaction(jsonObj);
                        //add the transaction to the database
                        dataBase.addTransactionToDB(transaction);
                        //update the user-interface about the last transaction in the system
                        DATA_STATUS transactionStatus = monitoringLogic.getStatus(transaction);
                        monitoringLogic.updateUI(transaction.getUuid(), transaction.getSender(), transaction.getReceiver(), transactionStatus);
                        Thread.sleep(1000);
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            };
            addTransactionToDBThread.start();
        } catch (Exception e) {
            log.error("Error parsing record", e);
            System.exit(1);
        }
    }

    synchronized (lock) {
        if (largestTimestamp.get() < timestamp) {
            log.info(String.format(
                    "Found new larger timestamp: %d (was %d), clearing state",
                    timestamp, largestTimestamp.get()));
            largestTimestamp.set(timestamp);
            sequenceNumbers.clear();
        }

        // Only add to the shared list if our data is from the latest run.
        if (largestTimestamp.get() == timestamp) {
            sequenceNumbers.addAll(seqNos);
            Collections.sort(sequenceNumbers);
        }
    }
    try {
        checkpointer.checkpoint();
    } catch (Exception e) {
        log.error("Error while trying to checkpoint during ProcessRecords", e);
    }
}

这是我的UI控制器:

package com.userInterface;

import com.DATA_STATUS;
import com.Main;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.util.*;

public class UIController implements Observer {
    @FXML
    private TableView<Record> table = new TableView<Record>();
    @FXML
    public TableColumn<Record, String> legalFlow1 = new TableColumn<Record, String>();
    @FXML
    public TableColumn<Record, String> legalFlow2 = new TableColumn<Record, String>();
    @FXML
    public TableColumn<Record, String> legalFlow3 = new TableColumn<Record, String>();
    @FXML
    public TableColumn<Record, String> legalFlow4 = new TableColumn<Record, String>();
    @FXML
    public TableColumn<Record, String> legalFlow5 = new TableColumn<Record, String>();
    @FXML
    public TableColumn<Record, String> legalFlow6 = new TableColumn<Record, String>();
    @FXML
    public Button exitButton = new Button();
    @FXML
    public Circle legalFlow1circle1 = new Circle();


    public Map<String, String> circles = new HashMap<String, String>();
    //last changes
    public UIController() {
        fillMap();
    }

    @FXML
    /**
     * The function exits from the game
     */
    public void pressExitButton() {
        Main.dropDBSchema();
        System.exit(0);
    }


    public void actionPerformed() {
        Platform.runLater(new Runnable() {
            @Override public void run() {
                handle();
            }
        });
    }

    public void handle() {
        legalFlow1circle1.setFill(Color.GOLD);
    }


        public void changeCircleColor(String key, DATA_STATUS status) {
        exitButton.fire();

    }

    private void fillMap() {
        this.circles.put("3866f99b-c412-4ce7-89dc-a53a06fa0fbc_ms1_ms2", "legalFlow1circle1");
        this.circles.put("3866f99b-c412-4ce7-89dc-a53a06fa0fbc_ms2_ms3", "legalFlow1circle2");
        this.circles.put("3866f99b-c412-4ce7-89dc-a53a06fa0fbc_ms3_ms4", "legalFlow1circle3");
        this.circles.put("a24854d9-1417-4468-852b-2fd442c844ce_ms3_ms1", "legalFlow2circle1");
        this.circles.put("a24854d9-1417-4468-852b-2fd442c844ce_ms1_ms2", "legalFlow2circle2");
        this.circles.put("332c464c-1b73-455e-800b-285683892285_ms4_ms2", "legalFlow3circle1");
        this.circles.put("332c464c-1b73-455e-800b-285683892285_ms2_ms3", "legalFlow3circle2");
        this.circles.put("332c464c-1b73-455e-800b-285683892285_ms3_ms1", "legalFlow3circle3");
        this.circles.put("ba3ef2e3-356e-4951-9854-f1803bb91653_ms2_ms1", "legalFlow4circle1");
        this.circles.put("ba3ef2e3-356e-4951-9854-f1803bb91653_ms1_ms4", "legalFlow4circle2");
        this.circles.put("ba3ef2e3-356e-4951-9854-f1803bb91653_ms4_ms3", "legalFlow4circle3");
        this.circles.put("b4fea051-d49c-46b9-a544-8cda3d4a8701_ms1_ms3", "legalFlow5circle1");
        this.circles.put("b4fea051-d49c-46b9-a544-8cda3d4a8701_ms3_ms2", "legalFlow5circle2");
        this.circles.put("02f77f86-0370-49a5-a26d-e3cfc2921d6c_ms3_ms2", "legalFlow6circle1");
        this.circles.put("02f77f86-0370-49a5-a26d-e3cfc2921d6c_ms2_ms4", "legalFlow6circle2");
        this.circles.put("02f77f86-0370-49a5-a26d-e3cfc2921d6c_ms4_ms1", "legalFlow6circle3");
    }

    @Override
    public void update(Observable o, Object arg) {
        actionPerformed();
    }
}

这是我的FXML文件:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Circle?>

<AnchorPane prefHeight="563.0" prefWidth="780.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.userInterface.UIController">
   <children>
      <Button id="exitButton" fx:id="exitButton" layoutX="787.0" layoutY="488.0" mnemonicParsing="false" onAction="#pressExitButton" text="Exit" />
      <TableView id="table" fx:id="table" layoutX="120.0" layoutY="199.0" prefHeight="200.0" prefWidth="730.0">
        <columns>
          <TableColumn id="legalFlow1" fx:id="legalFlow1" prefWidth="124.0" text="legalFlow1" />
            <TableColumn id="legalFlow2" fx:id="legalFlow2" prefWidth="121.0" text="legalFlow2" />
            <TableColumn id="legalFlow3" fx:id="legalFlow3" prefWidth="116.0" text="legalFlow3" />
            <TableColumn id="legalFlow4" fx:id="legalFlow4" prefWidth="120.0" text="legalFlow4" />
            <TableColumn id="legalFlow5" fx:id="legalFlow5" prefWidth="124.0" text="legalFlow5" />
            <TableColumn id="legalFlow6" fx:id="legalFlow6" prefWidth="124.0" text="legalFlow6" />
        </columns>
      </TableView>
      <ListView id="legalFlow4Content" fx:id="legalFlow4Content" layoutX="479.0" layoutY="225.0" prefHeight="173.0" prefWidth="123.0" />
      <ListView id="legalFlow5Content" fx:id="legalFlow5Content" layoutX="602.0" layoutY="225.0" prefHeight="173.0" prefWidth="123.0" />
      <ListView id="legalFlow6Content" fx:id="legalFlow6Content" layoutX="725.0" layoutY="225.0" prefHeight="173.0" prefWidth="123.0" />
      <ListView id="legalFlow3Content" fx:id="legalFlow3Content" layoutX="364.0" layoutY="225.0" prefHeight="173.0" prefWidth="115.0" />
      <ListView id="legalFlow2Content" fx:id="legalFlow2Content" layoutX="241.0" layoutY="225.0" prefHeight="173.0" prefWidth="123.0" />
      <ListView id="legalFlow1Content" fx:id="legalFlow1Content" layoutX="118.0" layoutY="225.0" prefHeight="173.0" prefWidth="123.0" />
      <Circle id="legalFlow1circle3" fx:id="legalFlow1circle3" fill="#d6d8da" layoutX="135.0" layoutY="363.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow1circle2" fx:id="legalFlow1circle2" fill="#d6d8da" layoutX="135.0" layoutY="311.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow1circle1" fx:id="legalFlow1circle1" fill="#d6d8da" layoutX="135.0" layoutY="258.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow2circle2" fx:id="legalFlow2circle2" fill="#d6d8da" layoutX="257.0" layoutY="342.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow2circle1" fx:id="legalFlow2circle1" fill="#d6d8da" layoutX="256.0" layoutY="281.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow3circle3" fx:id="legalFlow3circle3" fill="#d6d8da" layoutX="380.0" layoutY="364.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow3circle2" fx:id="legalFlow3circle2" fill="#d6d8da" layoutX="380.0" layoutY="309.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow3circle1" fx:id="legalFlow3circle1" fill="#d6d8da" layoutX="380.0" layoutY="254.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow4circle3" fx:id="legalFlow4circle3" fill="#d6d8da" layoutX="494.0" layoutY="363.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow4circle2" fx:id="legalFlow4circle2" fill="#d6d8da" layoutX="494.0" layoutY="308.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow4circle1" fx:id="legalFlow4circle1" fill="#d6d8da" layoutX="495.0" layoutY="254.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow5circle2" fx:id="legalFlow5circle2" fill="#d6d8da" layoutX="618.0" layoutY="340.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow5circle1" fx:id="legalFlow5circle1" fill="#d6d8da" layoutX="618.0" layoutY="278.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow6circle3" fx:id="legalFlow6circle3" fill="#d6d8da" layoutX="740.0" layoutY="363.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow6circle2" fx:id="legalFlow6circle2" fill="#d6d8da" layoutX="740.0" layoutY="310.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Circle id="legalFlow6circle1" fx:id="legalFlow6circle1" fill="#d6d8da" layoutX="740.0" layoutY="257.0" radius="12.0" stroke="BLACK" strokeType="INSIDE" />
      <Label layoutX="151.0" layoutY="250.0" text="MS1 to MS2" />
      <Label layoutX="150.0" layoutY="302.0" text="MS2 to MS3" />
      <Label layoutX="151.0" layoutY="355.0" text="MS3 to MS4" />
      <Label layoutX="270.0" layoutY="273.0" text="MS3 to MS1" />
      <Label layoutX="270.0" layoutY="334.0" text="MS1 to MS2" />
      <Label layoutX="396.0" layoutY="246.0" text="MS4 to MS2" />
      <Label layoutX="395.0" layoutY="301.0" text="MS2 to MS3" />
      <Label layoutX="396.0" layoutY="355.0" text="MS3 to MS1" />
      <Label layoutX="510.0" layoutY="246.0" text="MS2 to MS1" />
      <Label layoutX="508.0" layoutY="300.0" text="MS1 to MS4" />
      <Label layoutX="508.0" layoutY="355.0" text="MS4 to MS3" />
      <Label layoutX="634.0" layoutY="269.0" text="MS1 to MS3" />
      <Label layoutX="635.0" layoutY="331.0" text="MS3 to MS2" />
      <Label layoutX="756.0" layoutY="250.0" text="MS3 to MS2" />
      <Label layoutX="756.0" layoutY="300.0" text="MS2 to MS4" />
      <Label layoutX="756.0" layoutY="355.0" text="MS4 to MS1" />
   </children>
</AnchorPane>

最后,这是我的主要内容:

package com;

import com.kinesisdataconsumer.Consumer;
import com.kinesisdataproducer.Producer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.io.IOException;
import java.util.ArrayList;

@SpringBootApplication
public class Main extends Application {
    public static Stage stage = new Stage();
    public static Parent root = new Parent() {
    };
    public static DataBase dataBase;

    /**
     * the main method of the program
     */
    public static void main(String args[]) {
        String legalFlowsFileName = "src/main/resources/legalFlows.json";
        String transactionFileName = "src/main/resources/transaction.json";

        //create the data base and add the tables
        dataBase = new DataBase();

        //run the spring boot application
        SpringApplication springApplication = new SpringApplication(Main.class);
        springApplication.run(args);

        //parse all the legal flows from 'legalFlows.json'
        LegalFlowsFileParser legalFlowsFileParser = new LegalFlowsFileParser(legalFlowsFileName);
        ArrayList<LegalFlow> legalFlows = legalFlowsFileParser.parseFile();
        dataBase.addAllLegalFlowsToDB(legalFlows);

        //parse all the transactions from 'transactions.json'
        TransactionsFileParser transactionsFileParser = new TransactionsFileParser(transactionFileName);
        ArrayList<Transaction> transactions = transactionsFileParser.parseFile();

        //Kinesis Producer
        Producer producer = new Producer(transactions);
        try {
            producer.produceData();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //create the monitoring logic of the whole system
        MonitoringLogicImpl monitoringLogic = new MonitoringLogicImpl(dataBase, legalFlows);

        //Kinesis consumer
        Thread thread = new Thread(){
            public void run(){
                Consumer consumer = new Consumer(dataBase, transactions, monitoringLogic);
                consumer.consumeData();
            }
        };
        thread.start();

        Application.launch(Main.class, args);
    }

    public void start(Stage stage){
        this.stage = stage;
        FXMLLoader loader = new FXMLLoader();
        try {
            loader.setLocation(getClass().getResource("/UserInterface.fxml"));
            this.root = loader.load();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }
        stage.setTitle("Troubleshooting project");
        stage.setScene(new Scene(root, 900, 700));
        stage.show();
    }

    public static void dropDBSchema(){
        dataBase.dropSchema();
    }
}

这是监视逻辑类:

package com;

import com.userInterface.UIController;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import java.util.UUID;

public class MonitoringLogicImpl extends Observable implements MonitoringLogic {
    private DataBase database ;
    private ArrayList<LegalFlow> legalFlows;
    private final int MAX_DELAY = 20;
    private UIController uiController;
    List<Observer> observers = new ArrayList<Observer>();

    public MonitoringLogicImpl(DataBase database, ArrayList<LegalFlow> legalFlows){
        this.database = database;
        this.legalFlows = legalFlows;
        this.uiController = new UIController();
        attach(this.uiController);
    }

    public DATA_STATUS getStatus(Transaction transaction){
        LegalFlow legalFlow = getLegalFlowAccordingToLegalFlowUUID(transaction.getUuid());
        if(legalFlow.isTransactionExistInLegalFlow(transaction)){
            if(!isTransactionArrivedInDelay(transaction.getTimeSent(), transaction.getTimeReceived())){
                //first case : status COMPLETE - the transaction exist in the DB and it is part of a legal flow
                return DATA_STATUS.COMPLETE;
            } else {
                //third case : status DELAY - the time from the transaction sent until it's received is above the threshold value(MAX_DELAY)
                return DATA_STATUS.DELAY;
            }
        } else{
            //third case : status ERROR - the transaction is not exist in the DB
            return DATA_STATUS.ERROR;
        }
    }

    public void updateUI(UUID flowUUID, String sender, String receiver, DATA_STATUS status){
       // String key = flowUUID.toString()+"_"+sender+"_"+receiver;
        //this.uiController.changeCircleColor(key, status);
        notifyAllObservers();
    }

    public LegalFlow getLegalFlowAccordingToLegalFlowUUID(UUID legalFlowUUID){
        for (LegalFlow lf:this.legalFlows){
            if(lf.getUUID().toString().equals(legalFlowUUID.toString())){
                return lf;
            }
        }
        return new LegalFlow(UUID.fromString("00000000-0000-0000-0000-000000000000"),"ms0");
    }

    public boolean isTransactionArrivedInDelay(String timeSent, String timeReceived){
        DateTime dateTimeSent= null, dateTimeReceived = null;
        try {
            DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-mm-dd HH:mm:ss");
            dateTimeSent = formatter.parseDateTime(timeSent);
            dateTimeReceived = formatter.parseDateTime(timeReceived);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        long seconds = dateTimeReceived.getMillis() - dateTimeSent.getMillis();
         if((seconds/1000) > MAX_DELAY){
             return true;
         }
         return false;
    }
    //last changes
    public void attach(Observer observer){
        observers.add(observer);
    }

    public void notifyAllObservers(){
        Object obj = null;
        for (Observer observer : observers) {
            observer.update(this,obj);
        }
    }

}

1 个答案:

答案 0 :(得分:0)

所以您正在做的是添加一个$share = $this->Shares->get($id, [ 'contain' => ['Invoices'] ]); debug($share->invoice); 实例,这就是为什么您没有得到NullPointerException的原因,也是为什么您没有更新屏幕上实际使用的UIController的原因

您实际上在做什么:

UIController

您要调试的UIController与屏幕上的实例不同。我在您的一位同事中发布了您需要以某种方式将FXML创建的UIController传递到MonitoringLogicImpl的信息:

- new MonitoringLogicImpl
  - new UIController
  - Add to Observers
- Start FX
  - FXML Loads new UIController

但是,如果您开始添加其他需要更新的FXML屏幕,则会受到限制。您可能想做一些更通用的事情,其中​​您的应用程序是观察者,它将消息分发到邮箱,消息总线或其他内容。

关于应用程序,如果有人关闭应用程序会怎样?有没有重新启动GUI的方法,而无需重新启动整个服务?