我有一个模拟分布式环境的简单程序。我想通过使用GraphStream库来可视化处理器的行为。每个处理器都是一个线程,它们会进行一些计算,但不是一直进行,只有当我设置switch
变量时
while(running){
if(switch)
computate();
}
我已经写了一个类,它采用processorList并准备图形可视化。此任务有一个功能
public void adjustBFSGraph2(){
for(Edge e: this.g.getEdgeSet())
{
e.clearAttributes();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(Processor p : processorList)
{
p.getNode().setAttribute("ui.label", "Pid" +" " + p.getPID() +" "+"Dist: " + p.getFieldValue("bfs") + " " + "Parent" + " " + p.getFieldValue("parent"));
if(!p.getFieldValue("parent").equals("-1"))
{
Edge e = p.getNode().getEdgeBetween(p.getFieldValue("parent"));
if(e != null)
{
e.setAttribute("ui.color", p.getColor());
e.setAttribute("ui.label", "added" + p.getPID());
}
}
}
}
我的问题是,我看到边缘的颜色只是眨眼,然后颜色就消失了。看起来它在同一循环中添加了属性"ui.color"
并将其删除,但这怎么可能呢?@更新我已经编辑了我的代码,现在我可以在第一次循环后在thread.sleep()
中指定的时间内看到边,我不明白为什么在清除所有属性后,我实际上可以看到它们。以下是我如何调用我的函数
while(true)
{ i++;
//if any processor is not runing
boolean aux = false;
while(!aux) {
for (Processor proc : s.processorList) {
aux = aux || proc.isEnabled();
}
aux = !aux;
}
s.gp.adjustBFSGraph();
Thread.sleep(5000);
for(Processor proc: s.processorList)
{
proc.enable();
}
}
当Thread.sleep()
内部调节功能设置为小于100ms时,它再次开始闪烁。
因为可能有点不清楚我在做什么,所以我创建了一个较小的示例
这相当于我的处理器类
public class SomeObjectWithNode {
public Node n;
public Color c;
public SomeObjectWithNode(Node n)
{
Random rand = new Random();
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
Color randomColor = new Color(r, g, b);
c = randomColor;
this.n = n;
}
}
这是一个改变图形样式/绘制的类
public class TestDraw {
Vector<SomeObjectWithNode> n;
Graph g;
public TestDraw(Vector<SomeObjectWithNode> k, Graph g)
{
this.g= g;
this.n = k;
}
public void adjust()
{
Random rand = new Random();
for(Edge e: g.getEdgeSet())
{
e.clearAttributes();
}
for(SomeObjectWithNode k: n)
{
k.n.addAttribute("ui.color", k.c);
for(Edge e: k.n.getEdgeSet())
{
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
Color randomColor = new Color(r, g, b);
e.addAttribute("ui.color", randomColor);
}
}
}
}
这是主要的
public class TestGs {
public static void main(String[] args) {
Node lastNode;
TestDraw t;
Vector<SomeObjectWithNode> a = new Vector<SomeObjectWithNode>();
System.setProperty("gs.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
Graph g = new SingleGraph("test1");
g.display();
g.addAttribute("ui.stylesheet", "node { fill-mode: dyn-plain; size: 10px;} edge { fill-mode: dyn-plain; size: 2px;}");
a.add(new SomeObjectWithNode(g.addNode(Integer.toString(0))));
lastNode = g.getNode("0");
for(int i = 1; i < 10; i++)
{
a.add(new SomeObjectWithNode(g.addNode(Integer.toString(i))));
g.addEdge(Integer.toString(i-1).concat(Integer.toString(i)), a.get(i).n, lastNode);
lastNode = a.get(i).n;
}
t = new TestDraw(a,g);
while(true)
{
t.adjust();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
当我运行示例时,我们可以看到图形只在眨眼时显示颜色,而不是在Thread.sleep()
中显示时间。
主要问题是方法adjust()
中的e.clearAttributes();
。您不仅可以删除"ui.color"的所有属性。您可以使用e.setAttribute("ui.color", randomColor);
而不是e.addAttribute("ui.color", randomColor);
,并使用e.clearAttributes()
删除块(请参阅原始示例2)
我已经根据我的评论修改了你的代码,并在gist.github上分享了它。现在它每2秒改变一次颜色
PS:现在是关于失明的原因。我对GraphStream源代码进行了简短的研究(很抱歉,有很多java代码)。AbstractElement.java(只有有趣的方法):
public void clearAttributes() {
if (attributes != null) {
for (Map.Entry<String, Object> entry : attributes.entrySet())
attributeChanged(AttributeChangeEvent.REMOVE, entry.getKey(),
entry.getValue(), null);
attributes.clear();
}
}
...
public void setAttribute(String attribute, Object... values) {
addAttribute(attribute, values);
}
...
public void addAttribute(String attribute, Object... values) {
if (attributes == null)
attributes = new HashMap<String, Object>(1);
Object oldValue;
Object value;
if (values.length == 0)
value = true;
else if (values.length == 1)
value = values[0];
else
value = values;
AttributeChangeEvent event = AttributeChangeEvent.ADD;
if (attributes.containsKey(attribute)) // In case the value is null,
event = AttributeChangeEvent.CHANGE; // but the attribute exists.
oldValue = attributes.put(attribute, value);
attributeChanged(event, attribute, oldValue, value);
}
...
正如您所看到的,setAttribute和addAttribute非常相似。现在GraphicElement.java中的attributeChanged()实现:
@Override
protected void attributeChanged(AttributeChangeEvent event,
String attribute, Object oldValue, Object newValue) {
if (event == AttributeChangeEvent.ADD
|| event == AttributeChangeEvent.CHANGE) {
if (attribute.charAt(0) == 'u' && attribute.charAt(1) == 'i') {
if (attribute.equals("ui.class")) {
mygraph.styleGroups.checkElementStyleGroup(this);
// mygraph.styleGroups.removeElement( tis );
// mygraph.styleGroups.addElement( this );
mygraph.graphChanged = true;
} else if (attribute.equals("ui.label")) {
label = StyleConstants.convertLabel(newValue);
mygraph.graphChanged = true;
} else if (attribute.equals("ui.style")) {
// Cascade the new style in the style sheet.
if (newValue instanceof String) {
try {
mygraph.styleSheet.parseStyleFromString(
new Selector(getSelectorType(), getId(),
null), (String) newValue);
} catch (Exception e) {
logger.log(Level.WARNING, String.format("Error while parsing style for %S '%s' :", getSelectorType(), getId()), e);
}
mygraph.graphChanged = true;
} else {
logger.warning("Unknown value for style [" + newValue + "].");
}
} else if (attribute.equals("ui.hide")) {
hidden = true;
mygraph.graphChanged = true;
} else if (attribute.equals("ui.clicked")) {
style.pushEventFor(this, "clicked");
mygraph.graphChanged = true;
} else if (attribute.equals("ui.selected")) {
style.pushEventFor(this, "selected");
mygraph.graphChanged = true;
} else if (attribute.equals("ui.color")) {
style.pushElementAsDynamic(this);
mygraph.graphChanged = true;
} else if (attribute.equals("ui.size")) {
style.pushElementAsDynamic(this);
mygraph.graphChanged = true;
} else if (attribute.equals("ui.icon")) {
mygraph.graphChanged = true;
}
// else if( attribute.equals( "ui.state" ) )
// {
// if( newValue == null )
// state = null;
// else if( newValue instanceof String )
// state = (String) newValue;
// }
} else if (attribute.equals("label")) {
label = StyleConstants.convertLabel(newValue);
mygraph.graphChanged = true;
}
} else // REMOVE
{
if (attribute.charAt(0) == 'u' && attribute.charAt(1) == 'i') {
if (attribute.equals("ui.class")) {
Object o = attributes.remove("ui.class"); // Not yet removed
// at
// this point !
mygraph.styleGroups.checkElementStyleGroup(this);
attributes.put("ui.class", o);
mygraph.graphChanged = true;
} else if (attribute.equals("ui.label")) {
label = "";
mygraph.graphChanged = true;
} else if (attribute.equals("ui.hide")) {
hidden = false;
mygraph.graphChanged = true;
} else if (attribute.equals("ui.clicked")) {
style.popEventFor(this, "clicked");
mygraph.graphChanged = true;
} else if (attribute.equals("ui.selected")) {
style.popEventFor(this, "selected");
mygraph.graphChanged = true;
} else if (attribute.equals("ui.color")) {
style.popElementAsDynamic(this);
mygraph.graphChanged = true;
} else if (attribute.equals("ui.size")) {
style.popElementAsDynamic(this);
mygraph.graphChanged = true;
}
} else if (attribute.equals("label")) {
label = "";
mygraph.graphChanged = true;
}
}
}
注意:正如您在清除属性时所看到的,动态样式将通过方法popElementAsDynamic/pushElementAsDynamic
添加/删除。并在StyleGroup.java中实现这些方法:
/**
* Indicate the element has dynamic values and thus cannot be drawn in bulk
* operations. Called by the GraphicElement.
*
* @param element
* The element.
*/
protected void pushElementAsDynamic(Element element) {
if (dynamicOnes == null)
dynamicOnes = new HashSet<Element>();
dynamicOnes.add(element);
}
/**
* Indicate the element has no more dynamic values and can be drawn in bulk
* operations. Called by the GraphicElement.
*
* @param element
* The element.
*/
protected void popElementAsDynamic(Element element) {
dynamicOnes.remove(element);
if (dynamicOnes.isEmpty())
dynamicOnes = null;
}
当我们添加/setAttribute时,我们只在现有的hashmap中添加新元素。当我们使用clearAttributes时,我们为dynamicOnes
创建了新的实例HashMap。在这种情况下,我们可能会出现同步问题,这就是闪烁的原因。