JavaFX Node class provides two intersect methods:
intersects(Bounds localBounds);
and
intersects(double localX, double localY, double localWidth, double localHeight);
When and how can I use these methods?
as it name tells it is used to determine if a node is intersected with other node or not..
Example : If you're going to develop Zen pong game in javafx ,if ball hits the wall behind paddle then game over.
Code :
private Circle ball;
private Rectangle wall;
if(ball.intersects(wall.getBoundsInLocal()) {
//game over
}
Related
I want a Circle to respond to mouse events only when the mouse is on it's 'stroke' , i mean boundary. Of course, the circle has a transparent fill and a colorful stroke. Extending JavaFX Path looks painful to me, is there any way to do that with this Circle class?
Your solution does not work anymore in Java 9 but in your case you could just set the fill of the circle to null. This should have the same effect.
This solution doesn't work with Java 9:
Ok, finally I found an excellent way to do that. It may help others in the future:
javafx.scene.shape.Shape class has a Deprecated method
boolean impl_computeContains(double localX, double localY)
which invokes another method computeShapeContains(localX, localY, impl_configShape())
Now, scene graph decides whether a point is in a shape or not by
boolean contains(double localX, double localY) method from JavaFX.scene.Node which invokes that impl_computeContains method. So I had a look at those method and overrode the impl_computeContains mthod like this:
#Override
protected boolean impl_computeContains(double localX, double localY) {
float miterlimit =
(float) Utils.clampMin(getStrokeMiterLimit(), 1.0f);
return Toolkit.getToolkit().strokeContains(impl_configShape(), localX, localY, getStrokeType(),
Utils.clampMin(getStrokeWidth(), 0.0f), getStrokeLineCap(), getStrokeLineJoin(), miterlimit);
}
and boom!! it works!! All I did was, I removed the part which implemented what to do if the point was on the shape's interior part.
Firstly, i am sorry but i don't speak english very well. Secondly, i have a problem with nodes which are put in a gridpane. In fact, if the focus is taken by the first one wich is located on the top left side, when i push the tab key, the focus is not taken by the other which is located on the right.
People ask me to use the traversalEngine abstract class in order to solve this problem. Nevertheless, when i try to implement an engine object, it doesn't work if i put the parameters which are shown everywhere on the web:
TraversalEngine engine = new TraversalEngine(gridPane, false) {
It ask me to remove the parameters. If i do it, i don't have access to the trav method. In fact, it is the getRoot method which appears and can be implemented :
TraversalEngine engine = new TraversalEngine() {
#Override
protected Parent getRoot() {
// TODO Auto-generated method stub
return null;
}
}
Is there something which can be make in order to solve this problem ?
Thanks you for your help
Vinz
The traversal order for focusing nodes in a parent is the order in which they occur in the child list. Assuming every child contains at most one focusable node you could simply add the children line by line or reorder the children.
This could be done programmatically of course, but adding the children in the correct order in the first place would be more efficient...
public static int getColumnIndex(Node n) {
Integer i = GridPane.getColumnIndex(n);
return i == null ? 0 : i;
}
public static int getRowIndex(Node n) {
Integer i = GridPane.getRowIndex(n);
return i == null ? 0 : i;
}
grid.getChildren().sort(Comparator.comparingInt(ContainingClass::getRowIndex).thenComparingInt(ContainingClass::getColumnIndex));
I have a file of 3D data (time,x,y,z) and I want to create a JavaFX interactive animation with play, pause buttons, and the option of rotating the 3d objects.
I don't find in JavaFX any base example, it seems like I have to recreate my own mediaplayer.
Have a look at this library, F(X)yz is an open source
JavaFX 3D library that provides additional primitives, composite objects, controls and data visualizations that the base JavaFX 8 3D packages do not have.
There are several components that may help you. For instance, all the TexturedMesh subclasses are 3D shapes that allow using mathematical expressions to create contour plots (by using textures).
As an example, have a look at the icosahedron test.
private IcosahedronMesh ico;
private DensityFunction<Point3D> dens = p-> (double)p.x*p.y*p.z;
#Override
public void start(Stage primaryStage) throws Exception {
...
ico = new IcosahedronMesh(5,1f);
ico.setTextureModeVertices3D(1530,dens);
Group sceneRoot = new Group(ico);
Scene scene = new Scene(sceneRoot, 800, 600, true, SceneAntialiasing.BALANCED);
...
}
This short snippet will create something like this:
Now you can add some animation:
long lastEffect = System.nanoTime();
AtomicInteger count=new AtomicInteger();
AnimationTimer timerEffect = new AnimationTimer() {
#Override public void handle(long now) {
if (now > lastEffect + 50_000_000l) {
double t=count.getAndIncrement()%10;
dens = p->(double)(p.x+t)*(p.y+t)*(p.z+t);
ico.setDensity(dens);
lastEffect = now;
}
}
};
timerEffect.start();
and you will see something like this.
You could add on top of the subscene the usual media player controls, and bind them to the animation. Also you can add other animations to rotate the 3D shapes.
So the only thing you will have to add is a way of passing your data files to the shapes... You can add a feature request on the F(X)yz repository, providing some specific format of the data, the shapes you need...
For more information, you can also have a look at this post.
I am implementing drag and drag between two tree views. When a treeItem is dropped onto another treeView of treeItem a line connection is established between the two treeItems. This is working fine , but to have a connection initially without a drag and drop events is problem to me.
I am using treeCell for the drag and drop events.
final var treeCells = treeView.lookupAll( ".tree-cell" );
final var cells = new ArrayList<>( treeCells );
final var row = treeView.getRow( n );
final var node = cells.get( row );
if( node instanceof TreeCell ) {
#SuppressWarnings("rawtypes")
final var cell = (TreeCell) node;
System.out.println( "TREE CELL: " + cell );
}
As I thought, this turns out to be pretty difficult.
There is, by design, no way to get the TreeCell belonging to a given TreeItem. This is because of the "virtualization" design of the TreeView: a minimal number of TreeCells are created and these are updated with new TreeItems as required. Thus there typically won't be a TreeCell for every TreeItem, and the TreeItem represented by a given TreeCell may change at any point.
To make this work, first create an observable collection storing all the connections between the trees (e.g. an ObservableSet should work well). Represent the connections by some class that exposes start and end points which can be used for the lines.
Create custom cell factories for the trees. The cells they return should:
observe the item they are representing. If the item changes to one that is at an end of one or more connections, then the appropriate point on those connections should be bound to the appropriate transform of the coordinates of the cell.
If the item changes from one that is at the end of one or more connections, then unbind the appropriate end from the cell coordinates
observe the observable collection of connections. If one is added for which this cell's item is one end, then bind the coordinates as above
Note that when you bind the coordinates, you need to take into account the fact that the cells may move (e.g. via scrolling or via other changes in GUI layout). You also need to transform the coordinates from the cell's own coordinate system into the coordinate system of whichever pane is holding the connections (obviously, if these are connecting one tree to another, it must be some common scene graph ancestor of both trees).
And finally, you need some housekeeping. The connections need to make sure they either become invisible, or are removed from the scene if they are no longer bound at one or more ends.
I created an example. I just created some simple controls for generating the connections, but you could easily do this with drag and drop instead. The class encapsulating the view of the connection is AssignmentView; it uses Assignment to represent the actual data that is connected. The ConnectedTrees class is the main application and most of the interesting controller-type work is in there. The remaining classes are just data representation. The example is all Java 8; I think it would be much uglier in JavaFX 2.2.
This solution uses recursion calls to traverse the nodes tree of the tree view.
Normally this recursion shouldn't be dangerous as there is only limited nodes number (TreeCell's instances are reused by TreeView):
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import java.util.List;
public class TreeViewExplore {
/**
* Returns a cell for the tree item given. Or null.
*
* #param treeItem tree item
* #param treeView tree view
* #return tree cell
*/
public static TreeCell findCellByItem(TreeItem treeItem, TreeView treeView) {
return recursiveFindCellByItem(treeItem, treeView);
}
private static TreeCell recursiveFindCellByItem(TreeItem treeItem, Node node) {
if (node.getStyleClass().contains("tree-cell")
&& TreeCell.class.isAssignableFrom(node.getClass())
&& ((TreeCell) node).getTreeItem() == treeItem)
return (TreeCell) node;
if (!Parent.class.isAssignableFrom(node.getClass()))
return null;
List<Node> nodes = ((Parent) node).getChildrenUnmodifiable();
if (nodes == null) return null;
for (Node n : nodes) {
TreeCell cell = recursiveFindCellByItem(treeItem, n);
if (cell != null) return cell;
}
return null;
}
}
Usage:
// TreeItem treeItem = ...
TreeCell cell = TreeViewExplore.findCellByItem(treeItem, treeView);
// Check result:
System.out.println(
cell == null ? "cell is null" :
"(cell.getTreeItem() == treeItem) = "
+ (cell.getTreeItem() == treeItem));
Yet another solution using lookupAll() method. It is only for example here as it looks non very efficient for me because this method collects all nodes with CSS-selector given (and traverses all over the tree in any case):
public static TreeCell findCellByItem(TreeItem treeItem, TreeView treeView) {
return (TreeCell) treeView.lookupAll(".tree-cell").stream()
.filter(n -> ((TreeCell) n).getTreeItem() == treeItem)
.findFirst()
.orElse(null);
}
As far as I understand, duplicating nodes in JavaFX should be done with the Duplicator.duplicate function.
It works fine when duplicating nodes whose types are included in JavaFX library, for example
def dup = Duplicator.duplicate(Rectangle{x:30 y:30 width:100 height:100});
dup.translateX = 10;
insert dup into content;
would insert a black rectangle to the scene.
However if I define a new class in the following way:
class MyRect extends Rectangle {}
Or
class MyRect extends CustomNode {
override function create() {Rectangle{x:30 y:30 width:10 height:10}}
}
It gives me the following runtime error
Type 'javafxapplication1.NumberGrid$MyRect' not found.
Where of course javafxapplication1.NumberGrid are the package and file the MyRect class is in.
This guy at Sun's forums had the same problem, but I don't see any answer in there.
Or maybe I'm doing that the wrong way, and there's a better approach for duplicating custom nodes?
update: Trying to duplicate Group worked, but trying to duplicate Stack yields the same error.
According to the documentation, it's supposed to support all types supported in FXD including Node, but maybe it supports only some of Node's descendants?
I know its an old question, but did you try the following?
public class MyRect extends CustomNode, Cloneable {
override public function clone(): MyRect {
super.clone() as MyRect;
}
...
}
Which works for me via
var newRect = rect.clone();
Which is not a deep copy (but in my case I didn't need this)