I want to add new vertices and edges and create a graph using JGraph Library. I always get this java.lang.NullPointer exception. I have created a class function createvertex to create new cells/vertices and drawing edges my connecting to ports. But the port is always shown as null even when I haven't declared it as null. Below is my code. Is anything wrong in my code?
public class HelloWorld {
public static void main(String[] args) {
// Construct Model and Graph
GraphModel model = new DefaultGraphModel();
GraphLayoutCache view= new GraphLayoutCache(model,new DefaultCellViewFactory());
JGraph graph = new JGraph(model,view);
// Control-drag should clone selection
graph.setCloneable(true);
// Enable edit without final RETURN keystroke
graph.setInvokesStopCellEditing(true);
// When over a cell, jump to its default port (we only have one, anyway)
graph.setJumpToDefaultPort(true);
// Insert all three cells in one call, so we need an array to store them
DefaultGraphCell[] cells = new DefaultGraphCell[5];
DefaultPort[] port = new DefaultPort[4];
// Create Hello Vertex
cells[0] = createVertex("Hello", 20, 20, 40, 20, Color.BLACK, true);
port[0].setParent(cells[0]);
// Create World Vertex
cells[1] = createVertex("World", 140, 140, 40, 20, Color.ORANGE, true);
cells[1].add(port[1]);
cells[1].add(port[2]);
port[1].setParent(cells[1]);
port[2].setParent(cells[1]);
cells[3]= createVertex("Optical Cards",150,150,20,40,Color.GREEN, true);
cells[3].add(port[3]);
port[3].setParent(cells[3]);
// Create Edge
DefaultEdge[] edge = new DefaultEdge[2];
// Fetch the ports from the new vertices, and connect them with the edge
edge[0].setSource(cells[0].getChildAt(0));
edge[0].setTarget(cells[1].getChildAt(0));
cells[2] = edge[0];
edge[1].setSource(cells[1].getChildAt(1));
edge[1].setTarget(cells[3].getChildAt(0));
cells[4]=edge[1];
// Set Arrow Style for edge
int arrow = GraphConstants.ARROW_CLASSIC;
GraphConstants.setLineEnd(edge[0].getAttributes(), arrow);
GraphConstants.setEndFill(edge[0].getAttributes(), true);
GraphConstants.setLineEnd(edge[1].getAttributes(), arrow);
GraphConstants.setEndFill(edge[1].getAttributes(), true);
// Insert the cells via the cache, so they get selected
graph.getGraphLayoutCache().insert(cells);
// Show in Frame
JFrame frame = new JFrame();
frame.getContentPane().add(new JScrollPane(graph));
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static DefaultGraphCell createVertex(String name, double x,double y,double w,double h, Color bg, boolean raised) {
// Create vertex with the given name
DefaultGraphCell cell = new DefaultGraphCell(name);
// Set bounds
GraphConstants.setBounds(cell.getAttributes(), new Rectangle2D.Double(
x, y, w, h));
// Set fill color
GraphConstants.setGradientColor(cell.getAttributes(), Color.orange);
GraphConstants.setOpaque(cell.getAttributes(), true);
// Set raised border
if (raised)
GraphConstants.setBorder(cell.getAttributes(), BorderFactory
.createRaisedBevelBorder());
else
// Set black border
GraphConstants.setBorderColor(cell.getAttributes(), Color.black);
// Add a Port
DefaultPort port = new DefaultPort();
cell.add(port);
return cell;
}
}
DefaultPort[] port = new DefaultPort[4];
// Create Hello Vertex
cells[0] = createVertex("Hello", 20, 20, 40, 20, Color.BLACK, true);
port[0].setParent(cells[0]); // <---------- port[0] is null here, so you
// cannot call setParent()
Just because you initialized the port array doesn't mean that you can simply use the first DefaultPort element in the array. You need to populate the array with valid, non-null DefaultPort objects before trying to dereference an item in the array.
Related
So I have a list of Object, with a random height and weight. I also have a random number of those objects into a variable.
What I'm trying to do is to print all those object into the correct panel (I have 2 panel).
First of, my GUI and Object class (Blocks) are 2 separated class. Into the GUI, I'm doing this :
private JPanel initPanelBloc() {
panelBloc = new JPanel();
bloc = new Bloc(false);
panelBloc.add(bloc);
return panelBloc;
}
My Bloc class :
public class Bloc extends JPanel{
private int hauteur, largeur, nombreBloc;
private boolean premierPassage = true;
private ArrayList<Bloc> listeBlocRestant;
private Random rand = new Random();
public Bloc(boolean premierPassage) {
this.hauteur = 10 + rand.nextInt(50 - 10);
this.largeur = 10 + rand.nextInt(50 - 10);
listeBlocRestant = new ArrayList<Bloc>();
if(premierPassage == true) {
this.nombreBloc = 5 + rand.nextInt(30 - 5);
insererBlocList();
}
}
public ArrayList<Bloc> insererBlocList(){
premierPassage = false;
for(int i=0; i<nombreBloc; i++) {
Bloc bloc = new Bloc(false);
listeBlocRestant.add(bloc);
}
return listeBlocRestant;
}
public void paintComponent(Graphics2D g) {
Graphics2D g2 = (Graphics2D) g;
g2.fillRect(10, 20, this.largeur, this.hauteur);
}
I've got also a 3rd class where I call the GUI class :
public Optimisation() {
this.aff = new InterfaceGraphique();
}
And its in the above class where I need to do what I want.
I did not write in this what I want to do because I still don't know how to do it. Should I create a for each loop and take the list of blocks and for every blocks I want them to be print on the panel, with an x and y (of the fillRect) change between blocs ? I'm really lost, I tried to think about this yesterday but still no clue..
Cordially
I'm lost lol I do not understand everything in there since its with the click and so on
Well, the clicks are really not relevant to the painting concept.
The painting concept is you store the object you want to paint in an ArrayList. Then in the paintComponent() method you iterate through the ArrayList to paint each object.
In my example you have a method addRectangle(...) which adds one Rectangle object at a time. You can manually add a Rectangle by invoking this method without using a mouse. This allows you to add Rectangles of a different size/location/color.
For example you just change the code as follows:
private static void createAndShowGUI()
{
DrawingArea drawingArea = new DrawingArea();
drawingArea.addRectangle(new Rectangle(10, 10, 200, 100), Color.RED);
drawingArea.addRectangle(new Rectangle(210, 110, 20, 100), Color.BLUE);
Now the red rectangle will appear when you run the code.
The key points are:
you need a way to add the object you want to paint to your class
you then need to paint these objects in your paintComponent() method. You can't hardcode the painting the way you are currently doing it.
In your code your Bloc object will need to contain the information needed to paint the bloc.
I want to display a simple Graph with nodes IDs inside Nodes using Prefuse but this seems to be more complicated than it sounds.
Graph g = new Graph();
for (int i = 0; i < 3; ++i) {
Node n1 = g.addNode();
n1.setInt("label", 1); // I am trying to add a field in a node
Node n2 = g.addNode();
Node n3 = g.addNode();
g.addEdge(n1, n2);
g.addEdge(n1, n3);
g.addEdge(n2, n3);
}
g.addEdge(0, 3);
g.addEdge(3, 6);
g.addEdge(6, 0);
// add visual data groups
VisualGraph vg = m_vis.addGraph(GRAPH, g);
m_vis.setInteractive(EDGES, null, false);
m_vis.setValue(NODES, null, VisualItem.SHAPE, new Integer(Constants.SHAPE_STAR));
However, it seems that this field doesn't exist, it makes sense since I didn't add this field but there isn't an option to add a field neither. I am getting this exception referring to the n1.setInt("DEFAULT_NODE_KEY", 1) line:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at prefuse.data.Table.getColumn(Table.java:457)
at prefuse.data.Table.setInt(Table.java:1032)
at prefuse.data.tuple.TableTuple.setInt(TableTuple.java:215)
at prefuse.demos.AggregateDemo.initDataGroups(AggregateDemo.java:141)
at prefuse.demos.AggregateDemo.<init>(AggregateDemo.java:72)
at prefuse.demos.AggregateDemo.demo(AggregateDemo.java:182)
at prefuse.demos.AggregateDemo.main(AggregateDemo.java:176)
I am not sure how to use fields in Nodes. I tried to read the library's help but I don't manage to figure that out.
You may be looking for a LabelRenderer. In the example below, a LabelRenderer is constructed in such a way as to render nodes having the label GraphLib.LABEL, defined as "label":
LabelRenderer r = new LabelRenderer(GraphLib.LABEL);
The nodes comprising the Graph are given text via setString() using the same key, GraphLib.LABEL. For example, the root Node added to the Graph returned by GraphLib.getDiamondTree() is assigned the key GraphLib.LABEL and the value "0,0".
Node r = t.addRoot();
r.setString(LABEL, "0,0");
Later, when the Visualization runs, the renderer attempts to use text from the GraphLib.LABEL field.
import java.awt.Dimension;
import javax.swing.JFrame;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.layout.graph.ForceDirectedLayout;
import prefuse.activity.Activity;
import prefuse.controls.DragControl;
import prefuse.controls.PanControl;
import prefuse.controls.ZoomControl;
import prefuse.data.Graph;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.LabelRenderer;
import prefuse.util.ColorLib;
import prefuse.util.GraphLib;
import prefuse.visual.VisualItem;
/** #see https://stackoverflow.com/a/44274886/230513 */
public class Example {
private static final int W = 640;
private static final int H = 480;
public static void main(String[] argv) {
// -- 1. create the data ------------------------------------------------
Graph graph = GraphLib.getDiamondTree(3, 2, 1);
// -- 2. the visualization --------------------------------------------
// add the graph to the visualization as the data group "graph"
// nodes and edges are accessible as "graph.nodes" and "graph.edges"
Visualization vis = new Visualization();
vis.add("graph", graph);
vis.setInteractive("graph.edges", null, false);
// -- 3. the renderers and renderer factory ---------------------------
LabelRenderer r = new LabelRenderer(GraphLib.LABEL);
r.setRoundedCorner(8, 8); // round the corners
// create a new default renderer factory
// return our name label renderer as the default for all non-EdgeItems
// includes straight line edges for EdgeItems by default
vis.setRendererFactory(new DefaultRendererFactory(r));
// -- 4. the processing actions ---------------------------------------
ColorAction fill = new ColorAction("graph.nodes",
VisualItem.FILLCOLOR, ColorLib.rgb(200, 200, 255));
// use black for node text
ColorAction text = new ColorAction("graph.nodes",
VisualItem.TEXTCOLOR, ColorLib.gray(0));
// use light grey for edges
ColorAction edges = new ColorAction("graph.edges",
VisualItem.STROKECOLOR, ColorLib.gray(200));
// create an action list containing all color assignments
ActionList color = new ActionList();
color.add(fill);
color.add(text);
color.add(edges);
// create an action list with an animated layout
ActionList layout = new ActionList(Activity.INFINITY);
layout.add(new ForceDirectedLayout("graph"));
layout.add(new RepaintAction());
// add the actions to the visualization
vis.putAction("color", color);
vis.putAction("layout", layout);
// -- 5. the display and interactive controls -------------------------
Display d = new Display(vis) {
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
};
d.setSize(W, H); // set display size
d.pan(W / 2, H / 2); // pan to center
d.addControlListener(new DragControl());
d.addControlListener(new PanControl());
d.addControlListener(new ZoomControl());
// -- 6. launch the visualization -------------------------------------
JFrame frame = new JFrame("prefuse label example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(d);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true); // show the window
vis.run("color");
vis.run("layout");
}
}
I created a graph using JUNG, and I want to add a combobox that give the user the possibility to change the used layout (Circle, KK, FR, etc.)
But I couldn't do that.
that's how I visualize my graph:
// The Layout<V, E> is parameterized by the vertex and edge types
this.layout = new CircleLayout<Ressource,Float>(this.graph);
layout.setSize(new Dimension(500, 500)); // sets the initial size of the
// layout space
// The BasicVisualizationServer<V,E> is parameterized by the vertex and
// edge types
this.vv = new BasicVisualizationServer<Ressource, Float>(layout);
vv.setPreferredSize(new Dimension(550, 550)); // Sets the viewing area
// size
// Adjust the edges thikness
Transformer<Float, Stroke> edgeStroke = new Transformer<Float, Stroke>() {
#Override
public Stroke transform(Float arg0) {
return new BasicStroke(arg0);
}
};
vv.getRenderContext().setEdgeStrokeTransformer(edgeStroke);
// Show vertex and edge labels
vv.getRenderContext().setVertexLabelTransformer(
new Transformer<Ressource, String>() {
public String transform(Ressource r) {
return (r.nom);
}
});
vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller());
I tried to create a whole new BasicVisualizationServer object having each time a different Layout, but it didn't work, It sticks with the first layout (Circle in my case).
What is the best way to change layout ?
Thanks guys !
The source file for this demo (in your distribution) demonstrates how to do it: http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/samples/ShowLayouts.html
Basically, I'm trying to draw an empty health bar as an image, and then the actual health bar on top of it as another image so that I can just shorten the actual health bar when I need to update it. This is what I have so far:
TextureAtlas HUDatlas = new TextureAtlas(Gdx.files.internal("data/ui/HUDPack/textures.pack"));
emptyPlayerHealthBar = new Image(HUDatlas.findRegion("empty-health-bar"));
playerHealthBar = new Image(HUDatlas.findRegion("health-bar"));
//Creating the table
table = new Table(skin);
table.debug();
table.setBounds(0, 0, Gdx.graphics.getWidth(), 50);
table.left();
table.top();
table.add(playerHealthBar);
table.add(emptyPlayerHealthBar);
stage.addActor(table);
But this draws them side-by-side. How do I draw it so that the images are overlapping (empty-health-bar on the bottom and health-bar on top)?
I used this code to place a diamond over a box:
Image boxImage = new Image(Assets.instance.gifts.box);
Image diamondImage = new Image(Assets.instance.gifts.diamond);
Stack diamondBox = new Stack();
diamondBox.addActor(boxImage);
diamondBox.addActor(diamondImage);
tbl.add(diamondBox).width(20).height(20);
tbl.row();
You should probably use Scene2D's WidgetGroup (or, if you're not using layout managers, e.g. Table, Group) for that, e.g.
TextureAtlas HUDatlas = new TextureAtlas(Gdx.files.internal("data/ui/HUDPack/textures.pack"));
emptyPlayerHealthBar = new Image(HUDatlas.findRegion("empty-health-bar"));
playerHealthBar = new Image(HUDatlas.findRegion("health-bar"));
// creating the group
WidgetGroup group = new WidgetGroup();
group.addActor(playerHealthBar);
group.addActor(emptyPlayerHealthBar);
// creating the table
table = new Table(skin);
table.setBounds(0, 0, Gdx.graphics.getWidth(), 50);
table.debug().left().top().add(group);
stage.addActor(table);
Note that you can offset those bars simply by using .setPosition() on them, as usual with libGDX's 2.5D objects. Also, you can make your libGDX code more concise by using method chaining, although that's mostly a matter of style.
I am drawing a table in using libgdx game framework. Everything is rendered perfectly what I was trying to achieve. All I need now is to display cell borders of the table but I found nothing regarding this so far. I am also inclined to use the debug border lines to fullfill the purpose but also could not change the color of them.
Here is my code.
Table table = new Table();
table.setFillParent(true);
table.left().top();
table.add(new Label("Results", new LabelStyle(font, Color.BLACK))).colspan(2).expandX();
table.row();
table.add(new Label(text_you_score, new LabelStyle(font, Color.BLACK)));
table.add(new Label(text_actual_score, new LabelStyle(font, Color.BLACK)));
return table;
There are many properties available for the table and cell but not the border property.
We can also draw grid lines manually but that won't work perfectly on every device resolution I think. Any help or idea is highly appreciated. Thanks
This is based on libGDX 1.5.3:
A solution to this is to use a NinePatch as the background image for your Table.
NinePatch patch = new NinePatch(new Texture(Gdx.files.internal("background.png")),
3, 3, 3, 3);
NinePatchDrawable background = new NinePatchDrawable(patch);
Table table = new Table();
table.setBackground(background);
Using the number variables, you can modify the border radius. Make sure that this matches the png file.
Register your table for debug mode
table.debug();
Call in render() method
Table.drawDebug(stage);
Example
I achieved the display of the debug lines by converting from using a ShapeRenderer with the table.drawDebug(shapeRenderer shapes) call (which I couldn't get to work) to using a stage and adding the table as an actor.
The example linked in the answer above does show it clearly, but here is a short snippet for reference sake. This is on libGDX 1.5.3.
public class MyGdxGame extends ApplicationAdapter {
Texture img;
Stage stage;
#Override
public void create () {
img = new Texture("badlogic.jpg");
stage = new Stage();
final Skin skin = new Skin();
Label.LabelStyle style = new Label.LabelStyle(new BitmapFont(),Color.WHITE);
TextField.TextFieldStyle textFieldStyle = new TextField.TextFieldStyle();
textFieldStyle.fontColor = Color.WHITE;
textFieldStyle.font = new BitmapFont();
skin.add("default", style);
skin.add("default", textFieldStyle);
// Keep your code clean by creating widgets separate from layout.
Label nameLabel = new Label("Name:", skin);
TextField nameText = new TextField("",skin);
Label addressLabel = new Label("Address:", skin);
TextField addressText = new TextField("",skin);
Table table = new Table();
table.add(nameLabel); // Row 0, column 0.
table.add(nameText).width(100); // Row 0, column 1.
table.row(); // Move to next row.
table.add(addressLabel); // Row 1, column 0.
table.add(addressText).width(100); // Row 1, column 1.
table.setOriginX(0);
table.setOriginY(0);
table.setX(200);
table.setY(200);
table.debug();
stage.addActor(table);
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
public void resize (int width, int height) {
stage.getViewport().update(width, height, true);
}
public void dispose () {
stage.dispose();
}
}