我正在用JavaFx制作两个简单的JMS应用程序(一个用于发送方,另一个用于接收方)。
但是,我无法使用来自发送者的新到达消息来刷新接收者的GUI。
从调试中,我注意到接收者从服务器收到消息,但是接收者无法将其添加到我的ObservableList中(当然,这导致ListView的GUI中没有刷新)。
我在Internet上使用onMessage事件进行了查找,并对其进行了覆盖(以向其中的ObservableList添加一个项),但是它不起作用。引发事件后,没有元素添加到ObservableList。
这是我的接收者:
public class Administrator extends Application {
private ObservableList<String> observableList;
private final String DESTINATION_TYPE = "queue";
private final String RECEIVE_CHANNEL = "askDestination";
private final String SEND_CHANNEL = "answerDestination";
private MessageConsumer messageConsumer;
private MessageProducer messageProducer;
private Session session;
private Destination destination;
private Connection connection;
@FXML
public TextField tfMessage;
@FXML
public ListView<String> lvMessage;
@FXML
public Button btnSend;
@Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("administratorUI.fxml"));
stage.setTitle("Administrator");
stage.setScene(new Scene(root, 640, 480));
stage.setResizable(false);
stage.show();
}
@Override
public void init() throws Exception {
super.init();
lvMessage = new ListView<>();
tfMessage = new TextField();
//questionList = new ArrayList<>();
observableList = FXCollections.observableArrayList();
lvMessage.setItems(observableList);
initService(RECEIVE_CHANNEL, DESTINATION_TYPE);
getMessage(RECEIVE_CHANNEL);
//Platform.runLater(this::updateLV);
}
public static void main(String[] args) {
launch();
}
public void onButtonAnswerClick() {
String message = tfMessage.getText();
if (message.equals("")) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setContentText("Please enter your message!!");
alert.show();
return;
}
if (replyToQuestion(message, SEND_CHANNEL)) {
tfMessage.clear();
} else {
handleServiceError("Service Error", "Could not send the message to the service");
}
}
private void handleServiceError(String errorTitle, String errorText){
Alert error = new Alert(Alert.AlertType.ERROR);
error.setTitle(errorTitle);
error.setContentText(errorText);
}
private void updateLV(){
lvMessage.getItems().clear();
lvMessage.setItems(observableList);
}
private void initService(String targetDestination, String destinationType){
try {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "tcp://localhost:61616");
// connect to the Destination called “myFirstChannel”
// queue or topic: “queue.myFirstDestination” or “topic.myFirstDestination”
props.put((destinationType + "." + targetDestination), targetDestination);
Context jndiContext = new InitialContext(props);
ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("ConnectionFactory");
// to connect to the JMS
connection = connectionFactory.createConnection();
// session for creating consumers
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// connect to the receiver destination
//reference to a queue/topic destination
destination = (Destination) jndiContext.lookup(targetDestination);
} catch (NamingException | JMSException e) {
e.printStackTrace();
}
}
private boolean replyToQuestion(String message, String sendDestination) {
try {
initService(sendDestination, DESTINATION_TYPE);
// for sending messages
messageProducer = session.createProducer(destination);
// create a text message
Message msg = session.createTextMessage(message);
msg.setJMSMessageID("222");
System.out.println(msg.getJMSMessageID());
// send the message
messageProducer.send(msg);
//questionList.add(message);
updateLV();
return true;
} catch (JMSException e) {
e.printStackTrace();
return false;
}
}
private void getMessage(String receiveDestination) {
try {
initService(receiveDestination, DESTINATION_TYPE);
// this is needed to start receiving messages
connection.start();
// for receiving messages
messageConsumer = session.createConsumer(destination);
MessageListener listener = message -> {
try {
observableList.add(((TextMessage)message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
};
messageConsumer.setMessageListener(listener);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
我的发件人:
public class User extends Application implements MessageListener {
private static List<String> questions;
private final String DESTINATION_TYPE = "queue";
private final String RECEIVE_CHANNEL = "answerDestination";
private final String SEND_CHANNEL = "askDestination";
private String requestId;
private MessageConsumer messageConsumer;
private MessageProducer messageProducer;
private Session session;
private Destination destination;
private Connection connection;
@FXML
public Button btnSend;
@FXML
public TextField tfMessage;
@FXML
public ListView lvMessage;
@Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("userUI.fxml"));
stage.setTitle("Sender");
stage.setScene(new Scene(root, 640, 480));
stage.setResizable(false);
stage.show();
}
@Override
public void init() throws Exception {
super.init();
btnSend = new Button();
tfMessage = new TextField();
lvMessage = new ListView();
questions = new ArrayList<>();
initService(RECEIVE_CHANNEL, DESTINATION_TYPE);
getAnswer(RECEIVE_CHANNEL);
}
public static void main(String[] args){
launch(args);
}
public void onButtonSendClick(javafx.event.ActionEvent actionEvent) {
String message = tfMessage.getText();
if (message.equals("")) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setContentText("Please enter your question!!");
alert.show();
return;
}
if (sendQuestion(message, SEND_CHANNEL)) {
tfMessage.clear();
} else {
handleServiceError("Service Error", "Could not send the message tot the service");
}
}
private void handleServiceError(String errorTitle, String errorText){
Alert error = new Alert(Alert.AlertType.ERROR);
error.setTitle(errorTitle);
error.setContentText(errorText);
}
private void updateLV(){
lvMessage.getItems().clear();
lvMessage.getItems().addAll(questions);
}
private void initService(String targetDestination, String destinationType){
try {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "tcp://localhost:61616");
// connect to the Destination called “myFirstChannel”
// queue or topic: “queue.myFirstDestination” or “topic.myFirstDestination”
props.put((destinationType + "." + targetDestination), targetDestination);
Context jndiContext = new InitialContext(props);
ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("ConnectionFactory");
// to connect to the JMS
connection = connectionFactory.createConnection();
// session for creating consumers
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// connect to the receiver destination
//reference to a queue/topic destination
destination = (Destination) jndiContext.lookup(targetDestination);
} catch (NamingException | JMSException e) {
e.printStackTrace();
}
}
private boolean sendQuestion(String message, String sendDestination) {
try {
initService(sendDestination, DESTINATION_TYPE);
// for sending messages
messageProducer = session.createProducer(destination);
// create a text message
Message msg = session.createTextMessage(message);
msg.setJMSMessageID("111");
System.out.println(msg.getJMSMessageID());
// send the message
messageProducer.send(msg);
//questionList.add(message);
updateLV();
return true;
} catch (JMSException e) {
e.printStackTrace();
return false;
}
}
private void getAnswer(String receiveDestination) {
try {
initService(receiveDestination, DESTINATION_TYPE);
// for receiving messages
messageConsumer = session.createConsumer(destination);
messageConsumer.setMessageListener(this);
// this is needed to start receiving messages
connection.start();
} catch (JMSException e) {
e.printStackTrace();
}
}
@Override
public void onMessage(Message message) {
try {
questions.add(((TextMessage)message).getText());
requestId = message.getJMSMessageID();
System.out.println(requestId);
updateLV();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
接收者的FXML:
<GridPane hgap="10" prefHeight="400.0" prefWidth="600.0" vgap="10" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Administrator">
<padding>
<Insets bottom="10" left="10" right="10" top="10" />
</padding>
<Label text="Current question:" textFill="cornflowerblue" GridPane.columnIndex="0" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
<ListView fx:id="lvMessage" prefWidth="600" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="1">
</ListView>
<HBox spacing="10" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="2">
<TextField fx:id="tfMessage" prefHeight="61.0" prefWidth="504.0" promptText="Type your answer here...">
<font>
<Font size="15.0" />
</font>
</TextField>
<Button fx:id="btnSend" onAction="#onButtonAnswerClick" prefHeight="61.0" prefWidth="88.0" text="Send">
</Button>
</HBox>
<columnConstraints>
<ColumnConstraints />
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
<RowConstraints />
</rowConstraints>
</GridPane>
在接收者收到消息后,将引发该事件,因此我希望ListView随新消息一起更新。但是,没有元素添加到ObservableList => ListView中没有更新。
所以,我想问一下我做的是对还是错?
答案 0 :(得分:0)
原来,我在错误的线程上更新了ListView。对于那些仍然对答案感兴趣的人,我使用了Platform.runLater()
并将事件监听器注册到start
方法中(在stage.show()
之前)