JavaFX - SWT interop: application freezes - java

I am building a RCP application, based on Eclipse 3.5. Thanks to two articles (1, 2) that I've found on oracle.com, I have been able to implement a working RCP view, that displays a pie chart.
Unfortunately, if I close the view and reopen it, then the applications freezes and never comes back.
I am using JavaFX 2.2.7, under JDK 1.6.0.31 on Windows 7 X64.
Here is the code. The view is a standard subclass of org.eclipse.ui.part.ViewPart.
Composite panel = new Composite(parent, SWT.NONE);
RowLayout layout = new RowLayout();
panel.setLayout(layout);
FXCanvas fxCanvas = new FXCanvas(panel, SWT.NONE) {
#Override
public Point computeSize(int wHint, int hHint, boolean changed) {
getScene().getWindow().sizeToScene();
int width = (int) getScene().getWidth();
int height = (int) getScene().getHeight();
return new Point(width, height);
}
};
Scene scene = new Scene(new Group());
RGB rgb = panel.getBackground().getRGB();
Color color = Color.rgb(rgb.red, rgb.green, rgb.blue);
scene.setFill(color);
ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
pieChartData.add(new PieChart.Data("label1", 20));
pieChartData.add(new PieChart.Data("label2", 20));
pieChartData.add(new PieChart.Data("label3", 20));
pieChartData.add(new PieChart.Data("label4", 20));
pieChartData.add(new PieChart.Data("label5", 20));
Chart chart = new PieChart(pieChartData);
chart.setLegendSide(Side.RIGHT);
((Group) scene.getRoot()).getChildren().add(chart);
fxCanvas.setScene(scene);
Can anyone help?

The issue is solved. It was caused by some Thread naming tweaks somewhere else in the app. There are definitely things that one should not do. Overly relying on thread names is one of them. :)
A utility class was relying on thread names to run code in the UI thread and because JavaFX changes the name of the running thread, the utility class would not work correctly anymore.

Related

Prefuse : Organizing edges for clarity

I'm working on my personal family tree in Java/Eclipse, and happily bumped into prefuse as for graphic representation.
So far the result looks adaquate in regard to my database feed, but I'm still missing key points to make it easier to browse.
Point 1: verteces represent either a person or a union, and my graph is directed from older to younger members. This is reflected by the arrows on the edges. Yet I'd love to group the arrows in 1 direction only (I'm trying to group generations together if you like), but I can't start to find how to do that. For information, I'm using the NodeLinkTreeLayout as of now.
Point 2: aside from the graph itself, my app main window contains a second JPanel where I would like to modify / insert members. So I want to add an action to each node to call the procedures in the second JPanel. My research on how to access a java class from a node are inconclusive so far, it seems that all the examples from the starter prefuse pack are only based on graph interaction.
There it is. You might already have understood that I'm very new to prefuse and not a pro in Java. So any comment / directions / advice would really be appreciated. I will add a screecap and my graph code so you can see what could be done better.
Thank you for your time, and looking forward to reading your insights.
yorran
public class ShowGraph extends Display {
public static final String EDGES = "graph.edges";
public ShowGraph() {
super(new Visualization());
Graph mG = FamGraph.getGraph();
m_vis.addGraph("graph", mG);
m_vis.setInteractive("graphe.edges", null, false);
m_vis.setValue("graph.nodes", null, VisualItem.SHAPE, new Integer(Constants.SHAPE_ELLIPSE));
EdgeRenderer edgeR = new EdgeRenderer(Constants.EDGE_TYPE_CURVE, Constants.EDGE_ARROW_FORWARD);
LabelRenderer nodeR = new LabelRenderer("name");
nodeR.setRoundedCorner(8, 8);
nodeR.setHorizontalAlignment(Constants.LEFT);
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(nodeR);
drf.setDefaultEdgeRenderer(edgeR);
m_vis.setRendererFactory(drf);
int[] palette = new int[] {
ColorLib.rgb(255, 180, 180), ColorLib.rgb(190, 190, 255)
};
DataColorAction nFill = new DataColorAction("graph.nodes", "label", Constants.NOMINAL, VisualItem.FILLCOLOR, palette);
ColorAction edges = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(230));
ColorAction arrow = new ColorAction("graph.edges", VisualItem.FILLCOLOR, ColorLib.gray(230));
ColorAction text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0));
ActionList color = new ActionList();
color.add(nFill);
color.add(edges);
color.add(arrow);
color.add(text);
ActionList layout = new ActionList(Activity.INFINITY);
//layout.add(new ForceDirectedLayout("graph", true));
layout.add(new NodeLinkTreeLayout("graph"));
layout.add(new RepaintAction());
m_vis.putAction("color", color);
m_vis.putAction("layout", layout);
setSize(1200, 900); //size controlled by parent jpanel - Comment out after tests
pan(360, 250);
setHighQuality(true);
addControlListener(new DragControl());
addControlListener(new PanControl());
addControlListener(new ZoomControl());
addControlListener(new ZoomToFitControl());
m_vis.run("color");
m_vis.run("layout");
}
public static void main(String[] args) {
Fulltree.fireUp();
ShowGraph mG = new ShowGraph();
JFrame frame = new JFrame("My family chart");
JPanel thePanel = new JPanel();
frame.getContentPane().add(thePanel);
thePanel.add(mG);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
So after a lot of reseach, I'm answering to my own questions in case someone meets the same issues :
as for point 1 : ForceDirectedGraph is a lot better than NodeLinkTreeLayout, especially when your graph starts counting many members. Family branches make a lot more sense than viewing generations aligned.
as for point 2 : node related actions are the way to go, through a ControlListener:
addControlListener(new ControlAdapter() {
public void itemClicked(VisualItem item, MouseEvent e) {
// anything you need here
// even filter right and left click for a sub menu
}
});
One more thing : if you add actions to your graph (search, predicates...), make sure to stop them if you need to rebuild your graph at some point. If you don't, your actions will generate errors you will spend hours (if not days) to debug.

The same generated .JAR file is different in different computers

We have created an internal tool in Java -> Jar. It is created in JavaFX.
The .jar works fine in 9 out of 11 person's computers, but in 2 of them the .jar is in different size. Those 2 people have the window cut smaller for some reason. I will attach the images to show the difference as well.
First, the .jar in working PC (you can clearly see the edges of the .jar and all the fields are clearly visible:
Second, the .jar that is broken (I have painted the areas where you can see that the fields/window is being cut, it's just that the things that are in the frame don't fit there for some reason):
I can provide additional information if required. But currently it just seems that for those 2 computers the fields don't fit in the frame, can it be the difference in java versions or OS?
Edit:
Adding some information about the layouts etc (all the elements are in the grids):
#Override
public void start(final Stage stage) throws Exception {
final Group root = new Group();
GridPane grid0 = new GridPane();
final Scene scene = new Scene(root, 1030, 768);
final GridPane grid = new GridPane();
grid.setHgap(5); //The gap properties manage the spacing between the rows and columns.
grid.setVgap(5); //Vahe iga rea ja veeru vahel pmst.
grid.setPadding(new Insets(40, 20, 20, 20)); //while the padding property manages the space around the edges of the grid pane. Ehk kogu raami sisu vahe ��rtest.
//In this example, there are 10 pixels of padding on each side.
//grid.setGridLinesVisible(true); //N�itab t�pselt joonduse �ra
GridPane grid2 = new GridPane();
grid2.setHgap(5); //The gap properties manage the spacing between the rows and columns.
grid2.setVgap(5); //Vahe iga rea ja veeru vahel pmst.
grid2.setPadding(new Insets(40, 20, 20, 20)); //while the padding property manages the space around the edges of the grid pane. Ehk kogu raami sisu vahe ��rtest.
final GridPane grid3 = new GridPane();
grid3.setHgap(5); //The gap properties manage the spacing between the rows and columns.
grid3.setVgap(5); //Vahe iga rea ja veeru vahel pmst.
grid3.setPadding(new Insets(40, 20, 20, 20)); //while the padding property manages the space around the edges of the grid pane. Ehk kogu raami sisu vahe ��rtest.**strong text**
grid0.add(grid, 0, 0);
Line joon2 = new Line(0, 0, 0, 800);
grid0.add(joon2, 1, 0);
grid0.add(grid2, 2, 0);
final Line joon3 = new Line(0, 0, 0, 800);
grid0.add(joon3, 3, 0);
grid0.add(grid3, 4, 0);
root.getChildren().
add(grid0);
root.getChildren().
add(menuBar);
stage.setResizable(false); //Cannot resize the Bit!
stage.setScene(scene);
stage.show();
Thank you all for the responses, I managed to figure out the problem!
There were 2 options to fix this:
To change windows scaling under "Screen resolution".
I removed the hard-coded scene size and let the size be calculated by the size of the elements in the grids, so it would be dynamic for every computer.

LibGDX loading scene2D widgets very slow for first time, need suggestions

I started using scene2D in my LibGDX game to make a more professional looking login/register menu. The only problem is that switching to those menus is very long for menu navigation (3-5 sec).
I want to know if there is a better way to load them before hand, like during the game's initial loading screen. The thing is that once one of the menus is loaded, it loads very quick the second time.
I know for sure that its the create method of my screens that takes this long. Here is all that it is loading:
public void create(){
stage = new Stage(new StretchViewport(1920, 1080));
Gdx.input.setInputProcessor(stage);
loginBox = new Image(Textures.Gui.BOX);
loginBox.setSize(650, 1000);
loginBox.setPosition(635, 40);
stage.addActor(loginBox);
loginLBL = new Label("Login", Archipelo.SKIN, "basic-large-font", Color.LIGHT_GRAY);
loginLBL.setPosition(880, 955);
stage.addActor(loginLBL);
selectionHighlight = new Image(Textures.Gui.SELECTION_HIGHLIGHT);
selectionHighlight.setSize(540, 140);
stage.addActor(selectionHighlight);
usernameTF = new TextField("", Archipelo.SKIN);
usernameTF.setMaxLength(24);
usernameTF.setPosition(usernameTFx, usernameTFy);
usernameTF.setSize(400, 60);
stage.addActor(usernameTF);
passwordTF = new TextField("", Archipelo.SKIN);
passwordTF.setPasswordMode(true);
passwordTF.setPasswordCharacter('•');
passwordTF.setPosition(passwordTFx, passwordTFy);
passwordTF.setSize(400, 60);
stage.addActor(passwordTF);
usernameLBL = new Label("Username", Archipelo.SKIN, "basic-medium-font", new Color(1, 1, 1, 0.5f));
usernameLBL.setPosition(usernameTFx + 10, usernameTFy + 5);
stage.addActor(usernameLBL);
passwordLBL = new Label("Password", Archipelo.SKIN, "basic-medium-font", new Color(1, 1, 1, 0.5f));
passwordLBL.setPosition(passwordTFx + 10, passwordTFy + 5);
stage.addActor(passwordLBL);
remember = new CheckBox(" Remember Login?", Archipelo.SKIN);
remember.setPosition(rememberX, rememberY);
remember.getCells().get(0).size(30, 30);
stage.addActor(remember);
errorLBL = new Label("", Archipelo.SKIN, "basic-small-font", Color.RED);
errorLBL.setPosition(750, 650);
errorLBL.setWrap(true);
errorLBL.setBounds(750, 500, 400, 250);
stage.addActor(errorLBL);
continueLBL = new Label("Continue", Archipelo.SKIN, "basic-big-font", Color.WHITE);
continueLBL.setPosition(875, 100);
stage.addActor(continueLBL);
}
Also, I load the uiskin files before in the game's initial loading screen. Archipelo.SKIN is a static variable that refers to that uiskin. I also wanted to mention that my screen class is custom made and that whenever create() is called it is because a new screen instance is being created.
The thing that I don't get is why it takes so long to create the screen the first time and then every other time, it still goes through the same process except its much faster. Is there a way to make it faster the first time?
Thanks in advance. If you need more info by all means ask.
To summarize the comments...
The OP had a convenience class for texture references, that listed the textures like this:
public class Gui {
public static final Texture BOX = new Texture("box.png");
public static final Texture SELECTION_HIGHLIGHT= new Texture("selectionHighlight.png");
//...
}
Since they are declared static, they are members of the class, not an instance of a class. Static members of a class are all initialized at once, but only the first time the class or an instance of the class is accessed. This setup results in all the Gui textures getting loaded all at once at some inopportune, unplanned time.
The Texture's constructor Texture(String filename) causes a texture to be loaded from a file, which is time-consuming, so the loading of the Gui class takes a few seconds.
The solution is to not instantiate member texture variables in their declaration. Instantiate them within some method so you can decide exactly when they should be loaded.

Drawing Overlapping Images in Libgdx with a Table

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.

Using RowLayout does not give height to parent

I am using RowLayout for a container. The layout is having the Horizontal Orientation. I do not specify any height to the container. I expect it to get the height based on the height of its children. But GXT does not show the children of the container at all unless I explicitly specify height to it.
Is there a way to make the container to get the height depending on its children without specifying the height when using RowLayout with Horizontal Orientation?
public class RowLayoutNoHeight implements EntryPoint {
public void onModuleLoad() {
ContentPanel cp = new ContentPanel();
cp.setSize(300, 400);
final LayoutContainer innerPanel = new LayoutContainer();
innerPanel.setBorders(true);
innerPanel.setLayout(new RowLayout(Orientation.HORIZONTAL));
Text firstText = new Text("First text");
Text secondText = new Text("Second text");
// Here, innerPanel will not have any height. That is, I don't see the
// text components in the UI
innerPanel.add(firstText, new RowData(1, -1));
innerPanel.add(secondText, new RowData(1, -1));
Viewport viewPort = new Viewport();
cp.add(innerPanel);
viewPort.add(cp);
RootPanel.get().add(viewPort);
}
}
GWT version - 2.4
GXT Version - 2.2.5
Browser- IE 8 and Firefox 7.0.1
Thanks,
Ganesh
You have given your innerPanel a Layout which will only affect the widgets within that panel, simply add
cp.setLayout(new RowLayout(Orientation.HORIZONTAL));
after you declare your main panel.
If you could do a layout(true) for your container, you will find your problem disappears right away!

Categories

Resources