[英]Thread.sleep() freezes JFrame/GUI containing GraphStream graph
當我嘗試在調用 Thread,sleep() 的循環中更新它時,包含嵌入式單圖 ( Graphstream ) 的JFrame
凍結。 我已經嘗試在獨立圖形(顯示在它自己的)上使用相同的更新,並且它按預期工作。
我在 JFrame 中嵌入了一個圖形,如下所示(AppGraph.java):
public static ViewPanel init(){
graph.addAttribute("ui.stylesheet", styleSheet);
graph.setAutoCreate(true);
graph.setStrict(false);
graph.addAttribute("ui.quality");
graph.addAttribute("ui.antialias");
initGraph();
initNodes(graph);
return attachViewPanel();
}
private static ViewPanel attachViewPanel() {
Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
viewer.enableAutoLayout();
return viewer.addDefaultView(false);
}
private static void initGraph(){
FileSource fs = new FileSourceDOT();
String graph_filename = "graph.gv";
String absolute_path = System.getProperty("user.home") + File.separator + graph_filename;
fs.addSink(graph);
try {
fs.readAll(absolute_path);
} catch (IOException | NullPointerException e) {
e.printStackTrace();
} finally {
fs.removeSink(graph);
}
}
然后在 JFrame 類中調用它,如下所示:
/*AppWindow.java
* Set up graph
*/
GridBagConstraints graphConstraints = new GridBagConstraints();
graphConstraints.fill = GridBagConstraints.BOTH;
graphConstraints.gridx = 0;
graphConstraints.gridy = 1;
graphConstraints.weightx = 0.5;
graphConstraints.weighty = 0.5;
graphConstraints.gridwidth = 4;
graphConstraints.gridheight = GridBagConstraints.RELATIVE;
add(AppGraph.init(), graphConstraints);`
JFrame
有用於不同搜索算法(如 BFS)的按鈕。 在這些算法的執行過程中,遍歷的邊緣以固定的時間間隔着色,以創建一種如下所示的動畫效果:
//BFSAlgorithm.java
private void callBFS(Node startNode, Node goalNode) {
startNode.setAttribute("parent", "null");
startNode.setAttribute("level", 0);
startNode.setAttribute("visited?");
LinkedList<Node> queueFrontier = new LinkedList<>();
int level = 1;
queueFrontier.addLast(startNode);
while (!queueFrontier.isEmpty()) {
System.out.println("Level: " + (level - 1));
LinkedList<Node> next = new LinkedList<>();
for (Node node : queueFrontier) {
if (node == goalNode) {
System.out.println(node.getId() + ": Found Found Found!!!");
if (node != startNode) {
colorEdge(node);
}
return;
}
System.out.print(node.getId() + " visited \t");
if (node != startNode) {
colorEdge(node);
}
for (Edge edge : node.getEdgeSet()) {
Node opposite = edge.getOpposite(node);
if (!opposite.hasAttribute("visited?")) {
System.out.print(opposite.getId() + " enqueued \t");
opposite.setAttribute("level", level);
opposite.setAttribute("parent", node);
opposite.setAttribute("visited?");
next.addLast(opposite);
}
}
System.out.print("\n");
}
level++;
queueFrontier = next;
sleep();
}
}
private void colorEdge(Node node) {
Edge visitedEdge = node.getEdgeBetween(node.getAttribute("parent", Node.class));
visitedEdge.setAttribute("ui.color", 0.5);
sleep();
}
private void sleep() {
try {
Thread.sleep(AppWindow.speed);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
這個BFSAlgorithm
實現了DynamicAlgorithm
並擴展了SinkAdapter
。 我已經擴展了SinkAdapter
以使其能夠在算法運行時與視圖交互。 當我調用BFSAlgorithm
,當算法運行並且各種println
語句被sleep()
延遲時,GUI 會凍結並且沒有響應,直到執行之后所有訪問的邊緣都被着色。 我嘗試在我的AppGraph.java
實現ViewerListener
,如graphstream 文檔中所述,但它只會導致應用程序崩潰的無限循環:
/*...init() method from AppGraph.java*/
ProxyPipe fromViewer = viewer.newThreadProxyOnGraphicGraph();
fromViewer.addSink(graph);
fromViewer.pump();
while(loop) {
fromViewer.pump(); //
}
就像評論中建議的@Frakool 和@MadProgrammer 一樣,如果有人遇到類似問題,使用SwingWorker
和Swing Timer將提供所需的結果。 根據文檔:
通常,我們建議對 GUI 相關任務使用 Swing 計時器而不是通用計時器,因為 Swing 計時器都共享相同的、預先存在的計時器線程,並且 GUI 相關任務會自動在事件調度線程上執行。 但是,如果您不打算從計時器觸摸 GUI,或者需要執行冗長的處理,您可以使用通用計時器。
這是我如何使用它來阻止 gui 凍結。 我創建了一個使用Swing Timer
的私有內部SwingWorker
類,如下所示:
private class BFSTask extends SwingWorker<LinkedList<Node>, Node>{
private ArrayList<Node> visitedList;
private int visitedIndex = 0;
private boolean traversalDone = false;
private Timer traversal = new Timer(AppWindow.speed, new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
Node lastVisited = visitedList.get(visitedIndex);
Edge visitedEdge = lastVisited.getEdgeBetween(lastVisited.getAttribute("parent", Node.class));
visitedEdge.setAttribute("ui.color", 0.5);
visitedIndex++;
if(visitedIndex >= visitedList.size()){
traversal.stop();
traversalDone = true;
if(BFSAlgorithm.this.getPathToGoal() != null){
startTimer();
}
}
}
});
@Override
protected LinkedList<Node> doInBackground() throws Exception {
Node found = publishNodeBreadthFirst(getStartNode(), getGoalNode());
if (found != null) {
return getPathToGoal(found);
} else{
return null;
}
}
@Override
protected void process(List<Node> list) {
visitedList = (ArrayList<Node>) list;
traversal.start();
}
@Override
protected void done() {
try {
BFSAlgorithm.this.pathToGoal = get();
if(traversalDone && BFSAlgorithm.this.getPathToGoal() != null){
startTimer();
}
if(BFSAlgorithm.this.getPathToGoal() == null){
throw new NullPointerException("Goal Not Found.");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (NullPointerException e){
JOptionPane.showMessageDialog(getAppWindow(), "Goal Node Not Found!", "Error", JOptionPane.ERROR_MESSAGE);
getAppWindow().disableExceptClear();
getAppWindow().changeStatus("Goal node not found");
}
}
private LinkedList<Node> getPathToGoal(Node found) {
LinkedList<Node> path = new LinkedList<>();
Node parent = found.getAttribute("parent");
path.addLast(found);
while (parent != getStartNode()){
path.addLast(parent);
parent = parent.getAttribute("parent");
}
return path;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.