Thread.sleep()冻结包含GraphStream图的JFrame/GUI [英] Thread.sleep() freezes JFrame/GUI containing GraphStream graph
问题描述
我的JFrame
包含嵌入式单个图形( Graphstream )时,当我尝试在其中更新时会冻结调用Thread,sleep()的循环.我已经尝试过在独立图上使用相同的更新(显示为自己),并且按预期运行.
My JFrame
containing an embedded single graph (Graphstream) freezes when I try to update it in a loop that calls Thread,sleep(). I have tried using the same update on a standalone-graph (displayed on it's own) and it works as expected.
我在JFrame中嵌入了一个图,如下所示(AppGraph.java):
I have a single graph embedded in JFrame as follows (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类中调用此函数,如下所示:
Then this is called in the JFrame class as below:
/*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)的按钮.在执行这些算法的过程中,以固定的时间间隔对遍历的边缘进行着色,以创建一种动画效果,如下所示:
On the JFrame
are buttons for different search algorithms like BFS. During the execution of these algorithms, edges traversed are colored at fixed time intervals to create a sort of animation effect as shown below:
//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
以使其在算法运行时能够与View交互.当我调用BFSAlgorithm
时,在算法运行且各种println
语句延迟了sleep()
的同时,GUI冻结并且无响应,直到执行之后所有被访问的边缘都被着色为止.我尝试按照 graphstream文档所述在AppGraph.java
中实现ViewerListener
,但只会导致无限循环,使应用程序崩溃:
This BFSAlgorithm
implements DynamicAlgorithm
and extends SinkAdapter
. I have extended the SinkAdapter
to enable it to interact with the View as the algorithm runs. When I call the BFSAlgorithm
, while the algorithm runs and the various println
statements are delayed by sleep()
, the GUI freezes and is unresponsive until after execution before all the visited edges are then colored. I tried implementing ViewerListener
in my AppGraph.java
as is documented on the graphstream documentation but it only resulted in an infinite loop that crashed the application:
/*...init() method from AppGraph.java*/
ProxyPipe fromViewer = viewer.newThreadProxyOnGraphicGraph();
fromViewer.addSink(graph);
fromViewer.pump();
while(loop) {
fromViewer.pump(); //
}
推荐答案
如果有人遇到类似问题,请使用SwingWorker
和文档:
Like @Frakool and @MadProgrammer suggested in the comments, if anyone is having similar issues, using SwingWorker
and Swing Timer will provide the desired results. According to the documentation:
通常,对于与GUI有关的任务,我们建议使用Swing计时器而不是通用计时器,因为Swing计时器都共享相同的,预先存在的计时器线程,并且与GUI相关的任务会在事件调度线程上自动执行.但是,如果您不打算通过计时器触摸GUI,或者需要执行冗长的处理,则可以使用通用计时器.
In general, we recommend using Swing timers rather than general-purpose timers for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread. However, you might use a general-purpose timer if you don't plan on touching the GUI from the timer, or need to perform lengthy processing.
这是我用来停止gui冻结的方式.我创建了一个私有内部SwingWorker
类,该类使用Swing Timer
如下:
Here's how I used it to stop the gui freezing. I created a private inner SwingWorker
class that uses a Swing Timer
as below:
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;
}
}
这篇关于Thread.sleep()冻结包含GraphStream图的JFrame/GUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!