我正在尝试构建一个具有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);
}
}
}
答案 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的方法,而无需重新启动整个服务?