同步“前端"和“后端"在 Java(和 SWT)中
所以代码实际上工作正常 - 所有对象都按应有的方式进行了修改.在方法仍在运行时,似乎只有表面出现自我更新问题......
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...
我正在开发一个项目 atm,它基本上是关于解决推箱子谜题.现在,我们已经实现了 GUI 和算法的东西来解决这个谜题,但连接似乎很棘手.例如,在 GUI 中我选择解决"并且算法解决了谜题(在控制台中可见),但 GUI 不会更改为 InGame 视图(在调用 solve() 之前初始化.如果我这样做//switchToRoboControl() 它将立即显示 InGame!).在solve()完成后会切换到InGame,这很不方便,因为它应该显示图标在地图上移动并解决谜题.
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.
另外,如果有人对此有任何想法,为什么 InGame 会在 solve() 完成后出现,即使它在之前已初始化并且即使 isVisible() 返回 true?
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...
谢谢!
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());
}
}
(最后一部分是集成测试的模拟,稍后将被真实的方法调用所取代,例如getSolution()"等......这就是为什么在代码中实现解决方案的原因.)
(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.)
推荐答案
嗯,据我所知,您的问题是计算逻辑与 GUI 在同一线程中运行.这会导致计算期间不进行更新.您需要将计算放在后台线程中.此外,您的 Thread.sleep() 将导致 GUI 什么也不做.
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.
所以,把你的计算,例如在 Runnable 中.
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 会将您的更改转发到 gui 并立即返回到调用方法.UI 会在显示线程有时间时更新.
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.
相关文章