问题
Edit: So the code is actually working fine - all objects are modified as they should be. It's only the surface that seems to have issues updating itself while the method is still running...
I'm working on a project atm which is basically about solving a Sokoban-riddle. Now, we've implemented both the GUI and the algorithm stuff to solve the riddle, but the connection seems to be tricky. For example, in the GUI I choose "solve" and the algorithm solves the riddle (visible in the console), but the GUI doesn't change into the InGame view (which is initialized BEFORE solve() is called. If I do //switchToRoboControl() it will show the InGame immediately!). It will switch into InGame after solve() is done, which is inconventient since it's supposed to show the icons moving on the map and solving the riddle.
So my actual question is: how do I sychronize frontend and backend properly, so that if the backend makes a move and notifies the frontend, the frontend actually SHOWS what happened.
Also, if anyone has any ideas about that, why on earth does the InGame show up after solve() is done, even though it's initialized before and even though isVisible() returns true?
I can post the code if that helps, but there are thousands of lines so I thought maybe explaining the problem and getting a hint that would help me solve this could be enough...
Thanks!
public class SokobanGUIManager {
public SokobanGUIManager() {
this.display = new Display();
//initialsiere Shell
this.shell = new Shell(this.display);
shell.setText("Sokobots - The absolute best Sokoban-Solver you've ever seen!");
shell.setSize(735, 460);
//initialisiere Stack-Layout
this.layout = new StackLayout();
shell.setLayout(layout);
shell.layout();
//öffne Main-Menü;
goToMainMenu();
//Starte Fenster
this.shell.open();
//Lebensschleife
while (!this.shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
public class InGameGUI extends Composite {
...
public void initRoboControl() {
this.roboControl = new RoboControlGUI(this, manager, map, map.twoRobos(), this, this.roboStream); //RoboControlGUI is a child-Composite of InGameGUI
this.roboControl.setLayoutData(new RowData(300, 400));
this.layout();
this.guiCoordinator.setRoboControl(this.roboControl);
this.guiCoordinator.switchToRoboControl();
}
...
}
public class GUICoordinator {
...
protected void switchToRoboControl() {
if(this.roboControl != null) {
this.roboControl.setVisible(true);
System.out.println("RoboControl is visible");
this.roboCoordinator.switchToRoboControl();
} else {
System.out.println("Epic fail");
}
}
...
}
public class RoboCoordinator {
public void switchToRoboControl() { //TODO
this.gui.addToStreamEnd("switched to automatic control");
this.gui.deleteFirstLine();
this.gui.addToStreamEnd("the robots are calculating a solution. please wait");
try{ Thread.sleep(5000); } catch(Exception e) {}
this.map.setSolution(new Solution("1u:1l:1r:1d"));
this.gui.deleteFirstLine();
this.gui.deleteFirstLine();
this.gui.addToStreamEnd("robot 1 in direction u");
this.gui.addToStreamEnd("robot 1 in direction l");
this.gui.addToStreamEnd("robot 1 in direction r");
this.gui.addToStreamEnd("robot 1 in direction d");
try{ Thread.sleep(2000); } catch (Exception e) {}
this.map.moveRobo(1, 'u');
this.gui.updateMoves();
this.gui.updateSurface();
this.gui.deleteFirstLine();
System.out.println(this.map.toString());
System.out.println("Erster Zug fertig!");
try{ Thread.sleep(2000); } catch (Exception e) {}
this.map.moveRobo(1, 'l');
this.gui.updateMoves();
this.gui.updateSurface();
this.gui.deleteFirstLine();
System.out.println(this.map.toString());
System.out.println("Zweiter Zug fertig!");
try{ Thread.sleep(2000); } catch (Exception e) {}
this.map.moveRobo(1, 'r');
this.gui.updateMoves();
this.gui.updateSurface();
this.gui.deleteFirstLine();
System.out.println(this.map.toString());
try{ Thread.sleep(2000); } catch (Exception e) {}
this.map.moveRobo(1, 'd');
this.gui.updateMoves();
this.gui.updateSurface();
this.gui.deleteFirstLine();
System.out.println(this.map.toString());
}
}
(The last part is a simulation for the integrationtest and will later be replaced by real method calls like "getSolution()" and so on... That's why the solution is implemented in the code.)
回答1:
Well, as far as I can see your problem is that the calculation logic runs in the same thread as the GUI. This causes no updates during the calculation. You need to put the calculation in a background thread. Also, your Thread.sleep() will cause the GUI to do nothing.
So, put your calculation e.g. in a Runnable.
Runnable runnable = new Runnable(Display display) {
... some methods ...
@Override run() {
... your logic ...
display.asyncExec(new Runnable() {
run() {
// update your gui here
});
... some more logic ...
};
Display.asyncExec will forward you changes to the gui and return immediatly to the calling method. The UI will be updated when there is time in the display thread.
来源:https://stackoverflow.com/questions/24840762/synchronizing-frontend-and-backend-in-java-and-swt