如何在onMessage事件侦听器中将项目添加到ObservableList

时间:2019-03-25 10:17:26

标签: java javafx jms

我正在用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中没有更新。

所以,我想问一下我做的是对还是错?

1 个答案:

答案 0 :(得分:0)

原来,我在错误的线程上更新了ListView。对于那些仍然对答案感兴趣的人,我使用了Platform.runLater()并将事件监听器注册到start方法中(在stage.show()之前)