I'm new to Java and JavaFX and playing around with the Smack API for instant messaging. At moment I have a java file working for loggin in/out of a jabber server (Openfire), send message and receive messages. Log-in/out and send message is called from a javafx file. However, I'm struggling to get received messages to be displayed in javafx. I have tried to extend the PacketListener to invoke callbacks from java but I'm not sure whether this is correct at all the same applies to the class itself. I have got some infos from this website http://blog.crisp.se/perlundholm/2009/02/28/1235815701880.html
/*
* stage.fx
*/
package unfc;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.stage.StageStyle;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.paint.*;
import javafx.scene.layout.VBox;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import unfc.accordion;
import javafx.scene.shape.Rectangle;
import unfc.xmpp.xmpp_main;
import javafx.scene.control.TextBox;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
class MucListener extends PacketListener {
public var mediator: xmpp_main;
override public function processPacket(packet: Packet) {
if (packet instanceof Message) {
var message: Message = packet as Message;
FX.deferAction(function (): Void {
mediator.xmpp_create_chat(message.getBody());
});
}
}
}
public class stage {
public var getmsg: MucListener;
public var test: VBox;
public var test1: VBox;
public var test2: VBox;
public var message_new: TextBox;
public var uj = accordion{};
public var xmpp = xmpp_main{};
public var content: javafx.scene.Node;
public var content1: javafx.scene.Node;
public var content2: javafx.scene.Node;
public var testmsg = xmpp.msgArray;
public var bc = VBox {
visible: true
spacing: 10
content: [
test2 = VBox {
visible: true
width: 250
spacing: 10
content: [
Button {
text: "Button"
action: function () {xmpp.xmpp_connect();}
},
test = VBox {
visible: true
width: 250
spacing: 10
content: [content1,]
},
]
},
VBox {
visible: true
width: 250
spacing: 10
content: [
Button {
text: "Button1"
action: function () {xmpp.xmpp_disconnect();}
},
test1 = VBox {
visible: true
width: 250
spacing: 10
content: [content2,
message_new = TextBox {
columns: 12
selectOnFocus: true
},
Button {
text: "Send"
action: function () {xmpp.xmpp_create_chat(message_new.text); getmsg.mediator;}
}
]},
]
},
]
}
public var layout = Stage {
title: "IM"
style: StageStyle.TRANSPARENT
resizable: false
scene: Scene {
width: 500
fill: Color.TRANSPARENT
height: 400
content: [
Rectangle {
x: 10 y: 10 width: 390 height: 250 arcWidth: 30 arcHeight: 30 opacity: 1.0 fill: LinearGradient { startX: 0.0 startY: 0.0 endX: 0.0 endY: 10.0 stops: [ Stop { color: Color.BLACK offset: 0.0 }, Stop { color: Color.WHITE offset: 1.0 开发者_开发知识库 }, ] } },
VBox {
visible: true
content: bc
}
]
}
}
Below is the part from the java file which creates the chat and sends a message as well as starting the Message Listener.
/*
* xmpp_connections.java
*
*/
package unfc.xmpp;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.Message;
import javafx.async.RunnableFuture;
/**
* @author Chris
*/
public class xmpp_main {
.
.
.
.
.
public void xmpp_create_chat(String msg) {
ChatManager chatmanager = connection.getChatManager();
Chat newChat = chatmanager.createChat("admin@127.0.0.1", new MessageListener() {
@Override
public void processMessage(Chat chat, Message message) {
//msgArray.add( new String("Received message: " + message.getBody()) );
msgArray = "Received message: " + message.getBody();
System.out.println("Received message: " + message);
}
});
try {
newChat.sendMessage(msg);
} catch (XMPPException e) {
System.out.println("Error Delivering block");
}
}
It would be great if someone could point me to the right direction.
To get the data back into the JavaFX world, you need to set up a Java Interface and have your JavaFX class extend that interface. However, you can only manipulate JavaFX objects while on the main event thread. To do that, you need to call the deferAction method on the JavaFX entry class. Here is an example.
public void onMessage(final Message msg) {
try {
// must run this on the JavaFX Main thread
// If you don't you will eventually get exceptions
// in the JavaFX code.
Entry.deferAction( new Runnable() {
@Override
public void run() {
fxListener.onMessage(msg);
}
} );
} catch (Exception ex) {
Logger.getLogger(Subscriber.class.getName()).log(Level.SEVERE, null, ex);
}
}
Download the code examples for Chapter 12 - JavaFX Code Recipes for a more thorough example based on Java JMS.
Second, you should not be doing the connects, etc. in the main event thread. This will cause your gui to block if the connection takes a long time. It is better to do the interaction with the Java connection code in the background. Look at my blog entry http://blogs.oracle.com/clarkeman/entry/javafx_async_task to see examples of how to do this.
精彩评论