JavaFX - How to add array of MeshViews to group or scene - javafx

Update: I updated my code to loop through the list of meshviews and add each to the group using group.getChildren.add(meshview[i]) but still does not show up on screen. Thanks.
I am trying to add an array list of MeshView type to a scene in JavaFx based GUI. I was able to get an initial example to work where it was one MeshView, but now I have a case where the data that is read in from a file results in an array of MeshView type. I could not find a "add" or "addAll" type function on the Group type to let me loop through all of the elements and add them and I could not get the Group constructor to let me add the list at ones in the arguments. I am using a Group to contain them because the over all GUI makes use of a BorderLayout defined using an FXML file. So my initial version adds the meshview to a group along with some point lights and then that group is added to the center of the border layout using the set method of it. Any help would be appreciated. Thanks.
Ps. I think I may have just found an answer. I forgot the add method is under the get children:
group.getChildren().addAll(meshView, pointLight);
as the line above from another answer shows. But I would still be interested in hearing the best ways because I still am confused on how to deal with sitaution where you have say 20 meshviews that make up a part to be shown on screen and you want to combine those and appropriate lights etc and scale to fit in center or borderlayout. I'm guessin I can first all all meshviews using add and then add the lights but was not sure. Thanks again.

You can always add mesh views to any Node type object like Group or BorderLayout ex.
root.getChildren().add(meshView);
you can add as most as you can to this root object and translate the meshView in the scene
meshView.setTranslateX(200);
meshView.setTranslateY(200);
meshView.setTranslateZ(200);
and set the camera and lightpoints configuration and add them as well to the scene

Related

JavaFX 3D - Scene Camera Issues, SubScene Errors, and MeshViews not Visible

I will try to be as brief as possible while providing enough info so that someone might be able to help point me in the right direction. I am trying to add a 3D scene to the center or a borderpane that will contain a set of meshviews that I read from an obj file using an obj loader that has been well tested by others (so I'm confident it works). I will give my summary step by step and provide an image to show my progress and issues.
I start with my borderpane empty:
Next, I started by taking an example from a book that add me create three primitives and add them to a scene and changed it so that this is added to the center part of my borderpane. I created a method that is tied to the File/Open action that when I click File/Open, it calls that method and creates the primitives and adds them to the center of the borderpane:
Next, I tried to add a camera to the main scene that is created as part of the initial Application start method using the following lines:
(line 29 to 33 were commented out in earlier pictures)
However, this leads to the following issue where the borderpane is projected into the third dimension:
I then tried using a SubScene in the center of the borderpane but kept getting a lot of errors of the type nullpointerexception and the info was too vague for me to use to figure out what it was not happy about.
The other and more important issue that I am dealing with while trying to figure this out, is the final version meant to read a group of meshviews from an obj file and add them to the center does not work. The code reads the obj file and imports the meshviews from it. I have printed out to the console number of meshviews read and it matches what was in the test file, so I feel confident I'm using it correctly and this loader has been used a lot by others so has been tested. But when I try to change out and use that to add meshviews to the center I just get a blank center screen and a console printout showing it read the file and that it read the correct number of meshviews. I have not been able to find a good way to debug/figure this out. so could use some advice on that as well.
Thanks for any help you can provide.
instead of
Scene scene = new Scene(borderPane,sceneWidth,sceneHeight);
add this
Scene scene = new Scene(borderPane,sceneWidth,sceneHeight,true, SceneAntialiasing.BALANCED);
the last two parameters are = depthBuffer and antialiasing

Predefine Layout using Vis.js network

I would like to know if there is a way to inject a predefine layout in Vis.
I managed to save all coordinate of my nodes (X : Y) when i drag an drop each node, which is then saved to the database with a specified ID for each nodes.
What i struggle with is to specified this dataset to vis when i initialize a map with vis ( here is the doc of layout initilisation : http://visjs.org/docs/network/layout.html#)
i would like to put an array with my id nodes and position X Y so that it get saved when user change their layout.
It appears that it is not possible, but maybe there is a hidden way ?
Thanks in advance
This is quite possible:
to set initial layout, just add coordinates to each node (and disable physics so that they don't flow away from their positions):
nodes = [{id:1, label:'some', x:100, y:0 }, ... ];
options = { physics: false, ... };
to get current coordinates, use network.getPositions()
to save those at layout change, you probably want to use the dragEnd event and the on method (use network.getPositions() inside the event handler)
You can opt my implementation in the VisGraphPlugin repo (it's a plugin for TiddlyWiki Classic), just look for dragEnd and saveDataAndOptions, the latter may be of interest.
Instead of saving positions and id's you can simply use getSeed() method to save your layout configuration in a seed. Then, when you start the network again you can load this seed into the layout.randomSeed to have the same configuration.
The documentation for getSeed() says:
If you like the layout of your network and would like it to start in the same way next time, ask for the seed using this method and put it in the layout.randomSeed option.

Smoothly Updating QGraphicsscene

Hi I have managed to add a number of qgraphicsitems to a qgraphicsscene using the code below
def generate_graph_and_update_scene(self):
try:
local_params=locals() #for error log get local paramters
this_function_name=sys._getframe().f_code.co_name #for error log get function name
self.vertex_dict.clear()
self.clear() #clear graphicsscene
self.graph_pos.clear() #clear graph position holder object
#function that generates the node data
root_nodes=my_database_query.get_nodes_information()
for node in root_nodes:
# add nodes to nx.graph object
self.nx_graph.add_node(node['column1'])
# create networkx graph
self.graph_pos = nx.spring_layout(self.nx_graph, iterations=25,scale=10)
for node in self.nx_graph.nodes(): # Add nodes to qgraphicsscene
v=default_nodeobject.my_ellipse(node,self.graph_pos)
self.addItem(v) # Add ellipse to qgraphics scene
for edge in self.nx_graph.edges():
self.addItem(defaultedgeview.edgeview(edge[0], edge[1],self.graph_pos))#add edges to qgraphicscene
except:
#Exception handler
message=str(sys.exc_info())
message=message + str(local_params)+" "+ str(this_function_name)
print message
This allows me to add say 600 'nodes' to my qgraphics scene, however when I clear the scene and add another say 1500 nodes, adding the items blocks the UI and my whole application freezes for a few seconds.
Also whenever I am doing things like looping through the graphicsitems say looking for the nodes that have a certain property, again the main thread freezes while I am looping,
Could anyone suggest a good method of keeping the UI responsive while things are being done to the grpahicsscene/items in the scene.
Ideally would like to have smooth, non-blocking updates to the scene, even when I have a few thousand items showing.
The problem here is the management of each node as a graphics item. Adding and removing to a scene, as well as rendering each item is going to take time. With this many items, I suggest designing it differently.
Consider the node graph as a single, custom graphics item which stores a group of nodes and manages them as a single unit, rather than 600+ separate items.
Designed this way, you only add one item to the scene (the node graph) which allows rapid addition and removal of nodes and you will also see a performance improvement in rendering the scene, as all nodes are drawn in one call to paint().
Of-course, if you need to move nodes around by clicking and dragging them, you'll have to add additional code to handle detecting which node is being selected in the item and move it yourself.
However, this is the optimal way to handle such a large number of items in a scene.

How to listen to visible changes to the JavaFX SceneGraph for specific node

We created a small painting application in JavaFX. A new requirement arose, where we have to warn the user, that he made changes, which are not yet persisted and asking him, if the user might like to save first before closing.
Sample Snapshot:
Unfortunately there are a lot of different Nodes, and Nodes can be changed in many ways, like for example a Polygon point can move. The Node itself can be dragged. They can be rotated and many more. So before firing a zillion events for every possible change of a Node object to the canvas I`d like to ask, if anyone might have an idea on how to simplify this approach. I am curious, if there are any listeners, that I can listen to any changes of the canvas object within the scene graph of JavaFX.
Especially since I just want to know if anything has changed and not really need to know the specific change.
Moreover, I also do not want to get every single event, like a simple select, which causes a border to be shown around the selected node (like shown on the image), which does not necessary mean, that the user has to save his application before leaving.
Anyone have an idea? Or do I really need to fire Events for every single change within a Node?
I think you are approaching this problem in the wrong way. The nodes displayed on screen should just be a visual representation of an underlying model. All you really need to know is that the underlying model has changed.
If, for example, you were writing a text editor, the text displayed on the screen would be backed by some sort of model. Let's assume the model is a String. You wouldn't need to check if any of the text nodes displayed on screen had changed you would just need to compare the original string data with the current string data to determine if you need to prompt the user to save.
Benjamin's answer is probably the best one here: you should use an underlying model, and that model can easily check if relevant state has changed. At some point in the development of your application, you will come to the point where you realize this is the correct way to do things. It seems like you have reached that point.
However, if you want to delay the inevitable redesign of your application a little further (and make it a bit more painful when you do get to that point ;) ), here's another approach you might consider.
Obviously, you have some kind of Pane that is holding the objects that are being painted. The user must be creating those objects and you're adding them to the pane at some point. Just create a method that handles that addition, and registers an invalidation listener with the properties of interest when you do. The structure will look something like this:
private final ReadOnlyBooleanWrapper unsavedChanges =
new ReadOnlyBooleanWrapper(this, "unsavedChanged", false);
private final ChangeListener<Object> unsavedChangeListener =
(obs, oldValue, newValue) -> unsavedChanges.set(true);
private Pane drawingPane ;
// ...
Button saveButton = new Button("Save");
saveButton.disableProperty().bind(unsavedChanges.not());
// ...
#SafeVarArgs
private final <T extends Node> void addNodeToDrawingPane(
T node, Function<T, ObservableValue<?>>... properties) {
Stream.of(properties).forEach(
property -> property.apply(node).addListener(unsavedChangeListener));
drawingPane.getChildren().add(node);
}
Now you can do things like
Rectangle rect = new Rectangle();
addNodeToDrawingPane(rect,
Rectangle::xProperty, Rectangle::yProperty,
Rectangle::widthProperty, Rectangle::heightProperty);
and
Text text = new Text();
addNodeToDrawingPane(text,
Text::xProperty, Text::yProperty, Text::textProperty);
I.e. you just specify the properties to observe when you add the new node. You can create a remove method which removes the listener too. The amount of extra code on top of what you already have is pretty minimal, as (probably, I haven't seen your code) is the refactoring.
Again, you should really have a separate view model, etc. I wanted to post this to show that #kleopatra's first comment on the question ("Listen for invalidation of relevant state") doesn't necessarily involve a lot of work if you approach it in the right way. At first, I thought this approach was incompatible with #Tomas Mikula's mention of undo/redo functionality, but you may even be able to use this approach as a basis for that too.

Creating new objects with Game Maker GML

I'd like to know if there's a way to check if an object exists on a point, and if not, create a new one while snapping the new object to a grid? I know you can use this instance_create(x,y,obj_to_create); but that just places on a point no matter what and doesn't snap to a grid. Also, is there a global mouse click event in Game Maker?
Thanks!
well there are a few (almost similar) functions that allow you to do this... But most straight forward is to use position_meeting(x,y, obj)
so the could would become:
if (!position_meeting(x, y, obj_to_create)) {
instance_create(x,y,obj_to_create);
}
Now to snap to grid you'll have to create it at a snapped position:
instance_create(x div GRIDW, y div GRIDH, obj_to_create);

Resources