我正在使用JavaFX创建一个窗口,使用面向对象的方法,允许使用相同的基本框架创建不同类型的窗口。这些窗口将显示html内容。
我在尝试添加观察者时遇到了并发问题。
窗口:
public Window(String linkName, String fName, String wName, int width, int height, GuiObserver o) throws IOException {
wApp = new WindowApp();
wApp.setObserver(o);
new Thread(new Runnable() {
public void run() {
wApp.launch(WindowApp.class,linkName,fName,wName,""+width,""+height);
/*try {
wApp.launch(WindowApp.class,linkName,fName,wName,""+width,""+height);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
}
}).start();
}
这将创建窗口并设置观察者,但将启动放入新线程。我可以确认添加了观察者,但无法通知观察者。这是WindowApp类:
/**
* Instantiate the class with an html file
* THIS MUST NOT TAKE ANY PARAMETERS
*/
public WindowApp() throws IOException {}
@Override
public void start(Stage s) throws Exception {
this.stage = s;
//get the parameters
List<String> params = getParameters().getRaw();
String linkName = params.get(0);
updateHtmlFromFile(new File(params.get(1)));
windowName = params.get(2);
windowWidth = Integer.parseInt(params.get(3));
windowHeight = Integer.parseInt(params.get(4));
//create the window
stage.setWidth(windowWidth);
stage.setHeight(windowHeight);
Scene scene = new Scene(new Group());
browser = new WebView();
webEngine = browser.getEngine();
webEngine.setJavaScriptEnabled(true);
//add the link which will bind Java and Javascript functionality
Class jC = Class.forName(linkName);
Constructor jCon = jC.getConstructor(browser.getClass(),webEngine.getClass(),stage.getClass());
javascriptLink = (JavascriptLink) jCon.newInstance(browser,webEngine,stage);
javascriptLink.setObserver(gObserver);
//javascriptLink = new JavascriptLink(browser,webEngine,stage);
ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(browser);
webEngine.getLoadWorker().stateProperty()
.addListener(new ChangeListener<State>() {
@Override
public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
stage.setTitle(windowName);
}
}
});
webEngine.load(htmlUrl);
scene.setRoot(scrollPane);
stage.setScene(scene);
stage.show();
}
/**
* Add an observer to the javascript Link
* @param o
*/
public void setObserver(GuiObserver o) {
gObserver = o;
}
此对象还有一个“Javascript链接”,它在启动后与HTML文档交互:
package gui;
import java.io.FileNotFoundException;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class MainWindowJSLink extends JavascriptLink {
private GuiObserver gObserver;
/**
* This will be called by WindowApp when appropriate, and does not need to be called by a person
* @param b
* @param we
* @param st
* @throws FileNotFoundException
*/
public MainWindowJSLink(WebView b, WebEngine we, Stage st) throws FileNotFoundException {
super(b, we, st);
}
@Override
public void eventTriggered(String eventName) {
System.out.println("Event triggered -> "+eventName);
switch (eventName) {
case "codeEditorContentsChanged":
handleCodeEditorContentsChanged();
break;
}
//notify observers if necessary
this.triggerObserver(eventName, null);
}
/**
* Handle the event that the contents of the code editor have changed
* This will probably setup a timer to wait a few seconds until the user has stopped typing,
* then send the contents to the syntax highlighter and get the result back
*/
private void handleCodeEditorContentsChanged() {
//System.out.println(getJSCodeEditorContents());
}
/**
* Get the raw contents of the code editor (unedited and not stripped of html entities)
* @return
*/
public String getJSCodeEditorContents() {
String contents = (String) super.webEngine.executeScript("getCodeEditorContents()");
return contents;
}
/**
* Set the contents of the code editor
* @param contents String
* NOTE:
*/
public void setJSCodeEditorContents(String contents) {
super.webEngine.executeScript("setCodeEditorContents(`"+contents+"`)");
}
//observer observable stuff
@Override
public void setObserver(GuiObserver o) {
gObserver = o;
gObserver.setJS(this);
System.out.println("MainWindow -> observer set");
}
@Override
public void triggerObserver(String s, Object o) {
gObserver.trigger(s,o);
}
@Override
/**
* Handle information sent from the
*/
public void send(String s, Object o) {
//handle information sent to this object
}
}
不幸的是,gObserver.trigger没有执行。有趣的是,如果在调用触发器之前放入System.exit(0),程序将退出。但是,如果我在调用之后(或在相应的方法中)将它放入,则不是。
有人可以提供有关如何解决此并发问题的任何建议吗?如果您需要更多信息,请告诉我,我会提供。