using JavaFX, how can I place one shape on top of the other? - scala

I am trying to make a checkers game. I will have 64 rectangles, and some of the rectangles will have circles on top of them (representing a checkers piece). How can I do this (i.e. place one shape on top of the other)?
If it matters I'm using Scala, not Java (though the syntax is similar, at least for this part of the project...)

Wrap your shapes in another node; StackPane seems ideal for this. Set its alignment to Pos. CENTER to achieve the effect you want.
Bear in mind, this is not an entirely efficient solution as you will be creating 64 StackPanes. If you want to avoid that, then you would need to do some math to manually position your pieces above the desired game board location. This, however, should not be entirely difficult as you know the dimensions of your board squares, pieces, and how they are laid out.

CAG Gonzo's answer will work, but also be aware that if you place multiple nodes in the same cell in a grid pane, they will be placed on top of each other. This might work pretty well for you application:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class CheckerBoard extends Application {
private static final int BOARD_SIZE = 8 ;
private static final int SQUARE_SIZE= 40 ;
private static final int NUM_PIECES = 12 ;
#Override
public void start(Stage primaryStage) {
GridPane checkerBoard = new GridPane();
configureBoardLayout(checkerBoard);
addSquaresToBoard(checkerBoard);
Circle[] whitePieces = new Circle[NUM_PIECES];
Circle[] blackPieces = new Circle[NUM_PIECES];
addPiecesToBoard(checkerBoard, whitePieces, blackPieces);
BorderPane root = new BorderPane(checkerBoard);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
private void addPiecesToBoard(GridPane checkerBoard, Circle[] whitePieces,
Circle[] blackPieces) {
for (int i=0; i<NUM_PIECES; i++) {
whitePieces[i] = new Circle(SQUARE_SIZE/2-4, Color.WHITE);
whitePieces[i].setStroke(Color.BLACK);
checkerBoard.add(whitePieces[i], i%(BOARD_SIZE/2) * 2 + (2*i/BOARD_SIZE)%2, BOARD_SIZE - 1 - (i*2)/BOARD_SIZE);
blackPieces[i] = new Circle(SQUARE_SIZE/2 -4, Color.BLACK);
blackPieces[i].setStroke(Color.WHITE);
checkerBoard.add(blackPieces[i], i%(BOARD_SIZE/2) * 2 + (1 + 2*i/BOARD_SIZE)%2, (i*2)/BOARD_SIZE);
}
}
private void addSquaresToBoard(GridPane board) {
Color[] squareColors = new Color[] {Color.WHITE, Color.BLACK};
for (int row = 0; row < BOARD_SIZE; row++) {
for (int col = 0; col < BOARD_SIZE; col++) {
board.add(new Rectangle(SQUARE_SIZE, SQUARE_SIZE, squareColors[(row+col)%2]), col, row);
}
}
}
private void configureBoardLayout(GridPane board) {
for (int i=0; i<BOARD_SIZE; i++) {
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setMinHeight(SQUARE_SIZE);
rowConstraints.setPrefHeight(SQUARE_SIZE);
rowConstraints.setMaxHeight(SQUARE_SIZE);
rowConstraints.setValignment(VPos.CENTER);
board.getRowConstraints().add(rowConstraints);
ColumnConstraints colConstraints = new ColumnConstraints();
colConstraints.setMinWidth(SQUARE_SIZE);
colConstraints.setMaxWidth(SQUARE_SIZE);
colConstraints.setPrefWidth(SQUARE_SIZE);
colConstraints.setHalignment(HPos.CENTER);
board.getColumnConstraints().add(colConstraints);
}
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX 8 Dynamic Node scaling

I'm trying to implement a scene with a ScrollPane in which the user can drag a node around and scale it dynamically. I have the dragging and scaling with the mouse wheel working as well as a reset zoom, but I'm having trouble with the calculations to fit the node to the width of the parent.
Here is my code as an sscce.
(works) Mouse wheel will zoom in and out around the mouse pointer
(works) Left or right mouse press to drag the rectangle around
(works) Left double-click to reset the zoom
(doesn't work) Right double-click to fit the width
If I zoom in or out or change the window size, the fit to width does not work.
If anyone can help me with the calculations to fit the node to the width of the parent, I would very much appreciate it.
EDITED:
I marked the method that is not working correctly. It is fitWidth(), which is invoked by right mouse button double-clicking.
I edited the text of the question for clarity and focus
Hopefully this is more clear now.
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ZoomAndPanExample extends Application {
private ScrollPane scrollPane = new ScrollPane();
private final DoubleProperty zoomProperty = new SimpleDoubleProperty(1.0d);
private final DoubleProperty deltaY = new SimpleDoubleProperty(0.0d);
private final Group group = new Group();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
scrollPane.setPannable(true);
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
AnchorPane.setTopAnchor(scrollPane, 10.0d);
AnchorPane.setRightAnchor(scrollPane, 10.0d);
AnchorPane.setBottomAnchor(scrollPane, 10.0d);
AnchorPane.setLeftAnchor(scrollPane, 10.0d);
AnchorPane root = new AnchorPane();
Rectangle rect = new Rectangle(80, 60);
rect.setStroke(Color.NAVY);
rect.setFill(Color.NAVY);
rect.setStrokeType(StrokeType.INSIDE);
group.getChildren().add(rect);
// create canvas
PanAndZoomPane panAndZoomPane = new PanAndZoomPane();
zoomProperty.bind(panAndZoomPane.myScale);
deltaY.bind(panAndZoomPane.deltaY);
panAndZoomPane.getChildren().add(group);
SceneGestures sceneGestures = new SceneGestures(panAndZoomPane);
scrollPane.setContent(panAndZoomPane);
panAndZoomPane.toBack();
scrollPane.addEventFilter( MouseEvent.MOUSE_CLICKED, sceneGestures.getOnMouseClickedEventHandler());
scrollPane.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
scrollPane.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
scrollPane.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());
root.getChildren().add(scrollPane);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
class PanAndZoomPane extends Pane {
public static final double DEFAULT_DELTA = 1.3d;
DoubleProperty myScale = new SimpleDoubleProperty(1.0);
public DoubleProperty deltaY = new SimpleDoubleProperty(0.0);
private Timeline timeline;
public PanAndZoomPane() {
this.timeline = new Timeline(60);
// add scale transform
scaleXProperty().bind(myScale);
scaleYProperty().bind(myScale);
}
public double getScale() {
return myScale.get();
}
public void setScale( double scale) {
myScale.set(scale);
}
public void setPivot( double x, double y, double scale) {
// note: pivot value must be untransformed, i. e. without scaling
// timeline that scales and moves the node
timeline.getKeyFrames().clear();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.millis(200), new KeyValue(translateXProperty(), getTranslateX() - x)),
new KeyFrame(Duration.millis(200), new KeyValue(translateYProperty(), getTranslateY() - y)),
new KeyFrame(Duration.millis(200), new KeyValue(myScale, scale))
);
timeline.play();
}
/**
* !!!! The problem is in this method !!!!
*
* The calculations are incorrect, and result in unpredictable behavior
*
*/
public void fitWidth () {
double scale = getParent().getLayoutBounds().getMaxX()/getLayoutBounds().getMaxX();
double oldScale = getScale();
double f = (scale / oldScale)-1;
double dx = getTranslateX() - getBoundsInParent().getMinX() - getBoundsInParent().getWidth()/2;
double dy = getTranslateY() - getBoundsInParent().getMinY() - getBoundsInParent().getHeight()/2;
double newX = f*dx + getBoundsInParent().getMinX();
double newY = f*dy + getBoundsInParent().getMinY();
setPivot(newX, newY, scale);
}
public void resetZoom () {
double scale = 1.0d;
double x = getTranslateX();
double y = getTranslateY();
setPivot(x, y, scale);
}
public double getDeltaY() {
return deltaY.get();
}
public void setDeltaY( double dY) {
deltaY.set(dY);
}
}
/**
* Mouse drag context used for scene and nodes.
*/
class DragContext {
double mouseAnchorX;
double mouseAnchorY;
double translateAnchorX;
double translateAnchorY;
}
/**
* Listeners for making the scene's canvas draggable and zoomable
*/
public class SceneGestures {
private DragContext sceneDragContext = new DragContext();
PanAndZoomPane panAndZoomPane;
public SceneGestures( PanAndZoomPane canvas) {
this.panAndZoomPane = canvas;
}
public EventHandler<MouseEvent> getOnMouseClickedEventHandler() {
return onMouseClickedEventHandler;
}
public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
return onMousePressedEventHandler;
}
public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
return onMouseDraggedEventHandler;
}
public EventHandler<ScrollEvent> getOnScrollEventHandler() {
return onScrollEventHandler;
}
private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
sceneDragContext.mouseAnchorX = event.getX();
sceneDragContext.mouseAnchorY = event.getY();
sceneDragContext.translateAnchorX = panAndZoomPane.getTranslateX();
sceneDragContext.translateAnchorY = panAndZoomPane.getTranslateY();
}
};
private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
panAndZoomPane.setTranslateX(sceneDragContext.translateAnchorX + event.getX() - sceneDragContext.mouseAnchorX);
panAndZoomPane.setTranslateY(sceneDragContext.translateAnchorY + event.getY() - sceneDragContext.mouseAnchorY);
event.consume();
}
};
/**
* Mouse wheel handler: zoom to pivot point
*/
private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {
#Override
public void handle(ScrollEvent event) {
double delta = PanAndZoomPane.DEFAULT_DELTA;
double scale = panAndZoomPane.getScale(); // currently we only use Y, same value is used for X
double oldScale = scale;
panAndZoomPane.setDeltaY(event.getDeltaY());
if (panAndZoomPane.deltaY.get() < 0) {
scale /= delta;
} else {
scale *= delta;
}
double f = (scale / oldScale)-1;
double dx = (event.getX() - (panAndZoomPane.getBoundsInParent().getWidth()/2 + panAndZoomPane.getBoundsInParent().getMinX()));
double dy = (event.getY() - (panAndZoomPane.getBoundsInParent().getHeight()/2 + panAndZoomPane.getBoundsInParent().getMinY()));
panAndZoomPane.setPivot(f*dx, f*dy, scale);
event.consume();
}
};
/**
* Mouse click handler
*/
private EventHandler<MouseEvent> onMouseClickedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.getButton().equals(MouseButton.PRIMARY)) {
if (event.getClickCount() == 2) {
panAndZoomPane.resetZoom();
}
}
if (event.getButton().equals(MouseButton.SECONDARY)) {
if (event.getClickCount() == 2) {
panAndZoomPane.fitWidth();
}
}
}
};
}
}
I found the answer. I was looking at the wrong calculations, assuming it to be related to the translations. The real culprit was the calculation for the difference in scale. I simply changed this:
double f = (scale / oldScale)-1;
to this:
double f = scale - oldScale;

How does 3D picking work in JavaFX 8

Unfortunately I could not find any good tutorial for picking api.
Can anyone give me a brief tutorial about it or some useful links?
Update
world.setOnMouseClicked((event)->{
PickResult res = event.getPickResult();
System.out.println("res "+res);
//you can get a reference to the clicked node like this
if (res.getIntersectedNode() instanceof Node){
((Node)res.getIntersectedNode()).setTranslateZ(-50);
}
});
The code above only work on the first node that I click.
Does anyone know what is the problem?
It seems to work just fine without much understanding. My guess is it takes the element closest to the camera (ie. in front) in the 2D representation of where you clicked. It doesn't matter which face you click, it always gets the right node.
The code is very simple. I've made a scene with a Parent called world that has 3D elements.
package simple3dboxapp;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.PickResult;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class Simple3dBoxApp extends Application {
public Rotate rx = new Rotate();
{ rx.setAxis(Rotate.X_AXIS); }
public Rotate ry = new Rotate();
{ ry.setAxis(Rotate.Y_AXIS); }
public Rotate rz = new Rotate();
{ rz.setAxis(Rotate.Z_AXIS); }
Translate t = new Translate();
private final PerspectiveCamera camera = new PerspectiveCamera(true);
{camera.getTransforms().addAll(t, rz, ry, rx);}
Label data = new Label();{data.setWrapText(true);data.setPrefHeight(200);}
public Parent createContent() {
Group root = new Group();
for(int i = 0; i<10; i++){
Box box = new Box(50, 50, 50);
Text text = new Text("Hi "+i);
ImageView iv = new ImageView("file:apple-touch-icon.png");
Image im = iv.getImage();
Material m = new PhongMaterial(Color.CYAN, im, null, null, null);
box.setMaterial(m);
box.getTransforms().add(new Translate(-250 + i * 50 , -100, -100 + i * 50));
text.getTransforms().add(new Translate(-250 + i * 50 , 0, -100 + i * 50));
iv.getTransforms().add(new Translate(-250 + i * 50 , +100, -100 + i * 50));
root.getChildren().addAll(box,text,iv);
}
camera.setNearClip(1);
camera.setFarClip(2000);
camera.setFieldOfView(100);
// Use a SubScene
SubScene subScene = new SubScene(root, 500,500);
subScene.setFill(Color.ALICEBLUE);
subScene.setCamera(camera);
Group group = new Group();
group.getChildren().add(subScene);
return group;
}
#Override
public void start(Stage stage) {
VBox vbox = new VBox();
Parent world = createContent();
world.setFocusTraversable(true);
vbox.getChildren().addAll(world,data);
Scene scene = new Scene(vbox);
stage.setScene(scene);
stage.show();
world.setOnKeyPressed((evt)->{
switch (evt.getCode()){
case UP:
rx.setAngle(rx.getAngle()+5);
break;
case DOWN:
rx.setAngle(rx.getAngle()-5);
break;
case RIGHT:
t.setX(t.getX()+10);
//camera.setTranslateX(camera.getTranslateX()+10);
break;
case LEFT:
t.setX(t.getX()-10);
//camera.setTranslateX(camera.getTranslateX()-10);
break;
case Z:
double zoom = evt.isShortcutDown()?-10:+10;
t.setZ(t.getZ()+zoom);
//camera.setTranslateZ(camera.getTranslateZ()+zoom);
break;
}
});
world.setOnMouseClicked((event)->{
PickResult res = event.getPickResult();
data.setText("res "+res);
if (res.getIntersectedNode() instanceof Box){
((Box)res.getIntersectedNode()).setMaterial(
new PhongMaterial(event.isShiftDown() ? Color.BLACK : Color.RED));
}
});
}
public static void main(String[] args) {launch(args);}
}
And this is the result from clicking a Box
res PickResult [node = Box#1dc02a4, point = Point3D [x = 12.361420184603276, y = 15.984395060669844, z = -5.0], distance = 1866.0254037844388, texCoord = Point2D [x = 0.6236142018460328, y = 0.8196879012133969]
PickResult javadoc

Eclipse RCP - Combining table rows by drag and drop the arrows

I am new be in RCP development.
I want to create two tables with, each table contains different data.
Data from two tables have either 1 to 1 , 1 to many or many to 1 relationship.
And that can be done by drawing arrows between two tables.
For example,
**Row 1** **Row 2**
R1 V1 R2 V1
R1 V2 R2 V2
R1 V3 R2 V3
I want to draw arrows from R1V1 to ( R2V1 and R2V3 ) or vice a versa.
How can I show it graphically.
How can I find that which rows are combined by arrows.
Any help is appreciated.
--- Mandar
Here is the code that is based on the idea proposed by Nick. It is just to give an idea for someone who might wonder where to start to implement something like this shown below
This would let you click on any column on the left hand side table, then draws a line as your mouse moves on towards the right table, and anchors the line as soon as a column on the right hand side table is selected. It keeps a mapping between the left table row and right table row in a linked list as the mapping data model.
package sample;
import java.util.LinkedList;
import org.eclipse.draw2d.AutomaticRouter;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayeredPane;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.PolylineDecoration;
import org.eclipse.draw2d.XYAnchor;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class GraphicTableMapper {
private static Point sourcePosition;
private static PathFigure currentPath;
private static Figure bf;
private static Canvas canvas;
private static int sourceRow;
private static int targetRow;
private static LinkedList<RowMapper> rowmapList = new LinkedList<RowMapper>();
public static void main(String[] args) {
Display display = Display.getDefault();
final Shell shell = new Shell(display);
shell.setSize(550, 500);
shell.setLayout(new GridLayout(3, false));
final Table table = new Table(shell, SWT.MULTI | SWT.BORDER
| SWT.FULL_SELECTION);
table.setLinesVisible(true);
table.setHeaderVisible(true);
final String[] titles = { "Serial Number", "Whatever" };
for (int i = 0; i < titles.length; i++) {
TableColumn column = new TableColumn(table, SWT.NONE);
column.setText(titles[i]);
}
int count = 100;// create 100 rows in table
for (int i = 0; i < count; i++) {
TableItem item = new TableItem(table, SWT.NONE);
item.setText(0, "x");
item.setText(1, "y");
item.setText(2, "!");
item.setText(3, "this stuff behaves the way I expect");
item.setText(4, "almost everywhere");
item.setText(5, "some.folder");
item.setText(6, "line " + i + " in nowhere");
}
for (int i = 0; i < titles.length; i++) {
table.getColumn(i).pack();
}
table.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event event) {
Point pt = new Point(event.x, event.y);
TableItem item = table.getItem(pt);
if (item == null)
return;
for (int i = 0; i < titles.length; i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(pt)) {
int index = table.indexOf(item);
System.out.println("Item " + index + "-" + i);
sourcePosition = pt;
sourceRow = index;
currentPath = new PathFigure();
currentPath.setSourceAnchor(new XYAnchor(
new org.eclipse.draw2d.geometry.Point(-10,
event.y)));
currentPath
.setTargetAnchor(new XYAnchor(
new org.eclipse.draw2d.geometry.Point(
0, pt.y)));
bf.add(currentPath);
}
}
}
});
table.addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent arg0) {
if (currentPath != null) {
((XYAnchor) (currentPath.getTargetAnchor()))
.setLocation(new org.eclipse.draw2d.geometry.Point(
0, arg0.y));
}
}
});
canvas = new Canvas(shell, SWT.None);
canvas.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_GREEN));
LightweightSystem lws = new LightweightSystem(canvas);
bf = new BaseFigure();
lws.setContents(bf);
canvas.addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent arg0) {
if (currentPath != null) {
((XYAnchor) (currentPath.getTargetAnchor()))
.setLocation(new org.eclipse.draw2d.geometry.Point(
arg0.x > canvas.getSize().x - 5 ? canvas
.getSize().x - 5 : arg0.x, arg0.y));
}
}
});
GridData data2 = new GridData();
data2.verticalAlignment = SWT.TOP;
data2.grabExcessHorizontalSpace = false;
data2.grabExcessVerticalSpace = true;
data2.horizontalIndent = -10;
data2.widthHint = 200;
data2.heightHint = 1000;
canvas.setLayoutData(data2);
final Table table2 = new Table(shell, SWT.MULTI | SWT.BORDER
| SWT.FULL_SELECTION);
table2.setLinesVisible(true);
table2.setHeaderVisible(true);
data2 = new GridData();
data2.grabExcessHorizontalSpace = false;
data2.horizontalIndent = -10;
table2.setLayoutData(data2);
final String[] titles2 = { "Serial Number", "Whatever" };
for (int i = 0; i < titles.length; i++) {
TableColumn column = new TableColumn(table2, SWT.NONE);
column.setText(titles[i]);
canvas.redraw();
}
table2.addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent event) {
if (currentPath != null) {
Point pt = new Point(event.x, event.y);
TableItem item = table2.getItem(pt);
if (item == null)
return;
for (int i = 0; i < titles2.length; i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(pt)) {
((XYAnchor) (currentPath.getTargetAnchor()))
.setLocation(new org.eclipse.draw2d.geometry.Point(
canvas.getSize().x - 5, event.y));
}
}
}
}
});
int count2 = 100;// create 100 rows in table 2
for (int i = 0; i < count2; i++) {
TableItem item = new TableItem(table2, SWT.NONE);
item.setText(0, "x");
item.setText(1, "y");
item.setText(2, "!");
item.setText(3, "this stuff behaves the way I expect");
item.setText(4, "almost everywhere");
item.setText(5, "some.folder");
item.setText(6, "line " + i + " in nowhere");
}
for (int i = 0; i < titles.length; i++) {
table2.getColumn(i).pack();
}
table2.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event event) {
try {
Point pt = new Point(event.x, event.y);
TableItem item = table2.getItem(pt);
if (item == null)
return;
for (int i = 0; i < titles2.length; i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(pt)) {
int index = table2.indexOf(item);
targetRow = index;
System.out.println("Item " + index + "-" + i);
if (sourcePosition != null) {
add(event);
}
}
}
} finally {
sourcePosition = null;
sourceRow = -1;
targetRow = -1;
}
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
public static void add(Event event) {
bf.remove(currentPath);
PathFigure figure = new PathFigure();
figure.setSourceAnchor(currentPath.getSourceAnchor());
figure.setTargetAnchor(currentPath.getTargetAnchor());
bf.add(figure);
currentPath = null;
RowMapper mapper = new RowMapper();
mapper.sourceRow = sourceRow;
mapper.targetRow = targetRow;
if (!rowmapList.contains(mapper)) {
rowmapList.add(mapper);
}
}
class BaseFigure extends FreeformLayeredPane {
public BaseFigure() {
setLayoutManager(new FreeformLayout());
setBorder(new MarginBorder(5));
setBackgroundColor(ColorConstants.white);
setOpaque(true);
}
}
class PathFigure extends PolylineConnection {
public PathFigure() {
setTargetDecoration(new PolylineDecoration());
setConnectionRouter(new AutomaticRouter() {
#Override
protected void handleCollision(PointList list, int index) {
}
});
}
}
class RowMapper {
int sourceRow;
int targetRow;
#Override
public boolean equals(Object obj) {
if (obj instanceof RowMapper) {
RowMapper mapper = (RowMapper) obj;
return (sourceRow == mapper.sourceRow && targetRow == mapper.targetRow);
}
return false;
}
}
This is quite a difficult component to implement, I did one of these for Tibco Business Studio some time ago.
You'll need to place a Canvas between your two tables to draw the links on. You presumably have data models for your two tables, you'll also need a third model for storing the links and ensure that any modifications to this model trigger a refresh of the Canvas.
Next add drag and drop support to the two tables, dropping an item from table 1 onto table 2 should create a new item in your link model (thus triggering a Canvas refresh to draw the link).
Actually drawing the links in the right locations you'll have to work out yourself, but hopefully this gives you some ideas to start with.
Am I right in thinking that this implementation uses the mouse location to draw the arrows? So if you wanted to save / load a relationship you would have to save the x,y positions of the arrows and you'd have to make sure your components always stayed the same size?

add visual below finger swipe, Triangle strip like fruit ninja Andengine

I want to show a triangle strip when user swap finger on screen. I am not sure how to do it with AndEngine, using particle system or using sprites or using Triangle Strip algo...
I haven't wrote any code because I am struck that what to do. I am uploading an image please share your ideas.
Update
someone has done this in Iphone but unfortunately I am unfamiliar with language syntax please help me in understanding algo of this code https://github.com/hiepnd/CCBlade
**Effect I want **
Complete Android Project Download
http://www.andengine.org/forums/resources/complete-runnable-project/1301
I have done this code but could not get the desired effect...
package org.az.algo.examples;
import javax.microedition.khronos.opengles.GL10;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.particle.ParticleSystem;
import org.anddev.andengine.entity.particle.emitter.RectangleParticleEmitter;
import org.anddev.andengine.entity.particle.initializer.AlphaInitializer;
import org.anddev.andengine.entity.particle.initializer.ColorInitializer;
import org.anddev.andengine.entity.particle.initializer.GravityInitializer;
import org.anddev.andengine.entity.particle.initializer.RotationInitializer;
import org.anddev.andengine.entity.particle.modifier.AlphaModifier;
import org.anddev.andengine.entity.particle.modifier.ColorModifier;
import org.anddev.andengine.entity.particle.modifier.ExpireModifier;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.Toast;
public class ParticleSystemSimpleExample extends BaseExample {
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 720;
private static final int CAMERA_HEIGHT = 480;
// ===========================================================
// Fields
// ===========================================================
private Camera mCamera;
private BitmapTextureAtlas mBitmapTextureAtlas;
private TextureRegion mParticleTextureRegion;
private BitmapTextureAtlas mBitmapTextureAtlasStreak;
private TextureRegion mStreadTextureRegion;
private Sprite[] mSprite = new Sprite[20];
private int mIndex = 0;
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public Engine onLoadEngine() {
Toast.makeText(this, "Touch the screen to move the particlesystem.", Toast.LENGTH_LONG).show();
this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
}
#Override
public void onLoadResources() {
this.mBitmapTextureAtlas = new BitmapTextureAtlas(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mParticleTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, "gfx/particle_point.png", 0, 0);
this.mBitmapTextureAtlasStreak = new BitmapTextureAtlas(128, 16, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mStreadTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlasStreak, this, "gfx/streak1.png", 0, 0);
this.mEngine.getTextureManager().loadTextures(this.mBitmapTextureAtlas, this.mBitmapTextureAtlasStreak);
}
#Override
public Scene onLoadScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
// final CircleOutlineParticleEmitter particleEmitter = new CircleOutlineParticleEmitter(CAMERA_WIDTH * 0.5f, CAMERA_HEIGHT * 0.5f + 20, 80);
final RectangleParticleEmitter particleEmitter = new RectangleParticleEmitter(CAMERA_WIDTH * 0.5f, CAMERA_HEIGHT * 0.5f, 5f,5f);
// final PointParticleEmitter particleEmitter = new PointParticleEmitter(10, 10);
final ParticleSystem particleSystem = new ParticleSystem(particleEmitter, 100, 100, 1000, this.mParticleTextureRegion);
particleSystem.setParticlesSpawnEnabled(false);
scene.setOnSceneTouchListener(new IOnSceneTouchListener() {
#Override
public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_MOVE){
particleSystem.setParticlesSpawnEnabled(true);
particleEmitter.setCenter(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
mSprite[getIndex()].setPosition(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
mSprite[getIndex()].setVisible(true);
}else if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP){
particleSystem.setParticlesSpawnEnabled(false);
hideAll();
}else if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
particleSystem.reset();
}
return true;
}
});
particleSystem.addParticleInitializer(new ColorInitializer(1, 0, 0));
particleSystem.addParticleInitializer(new AlphaInitializer(0));
particleSystem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
// particleSystem.addParticleInitializer(new VelocityInitializer(-2, 2, -20, -10));
particleSystem.addParticleInitializer(new GravityInitializer());
// particleSystem.addParticleModifier(new ScaleModifier(0.5f, 1.0f, 0, 1.5f));
particleSystem.addParticleModifier(new ColorModifier(1, 1, 0, 0.5f, 0, 0, 0, 3));
particleSystem.addParticleModifier(new ColorModifier(1, 1, 0.5f, 1, 0, 1, 4, 6));
particleSystem.addParticleModifier(new AlphaModifier(0, 1, 0, 0.5f));
particleSystem.addParticleModifier(new AlphaModifier(1, 0, 2.5f, 3.5f));
particleSystem.addParticleModifier(new ExpireModifier(6, 6f));
scene.attachChild(particleSystem);
for(int i = 0; i < mSprite.length; i++){
mSprite[i] = new Sprite(-20, 0, mStreadTextureRegion);
mSprite[i].setVisible(false);
scene.attachChild(mSprite[i]);
}
return scene;
}
#Override
public void onLoadComplete() {
}
private int getIndex(){
if(mIndex >= mSprite.length -1){
mIndex = 0;
}
System.out.println("Index ........ "+mIndex);
return mIndex++;
}
private void hideAll(){
for(int i = 0; i<mSprite.length; i++){
mSprite[i].setVisible(false);
mSprite[i].setPosition(-CAMERA_WIDTH, 0);
}
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
image I used with this code is also attached
Updated
partial effect achieved.. but problem on fast swiping.. all complete projects are uploaded here http://www.andengine.org/forums/post31772.html#p31772
Here is a solution in LibGDX. It uses GL_TRIANGLE_STRIP.
https://github.com/mattdesl/lwjgl-basics/wiki/LibGDX-Finger-Swipe
The final solution uses two triangle strips and a custom texCoord attribute, allowing for us to use a lookup texture to achieve fake (but efficient) anti-aliasing. A more efficient/flexible anti-aliasing would use shaders and a single triangle strip. Use vertex attribute -1.0 for the top and 1.0 for the bottom edge of your swipe, and 1.0 for the tips. Then in the frag shader, use abs() -- so 0.0 means "center" and 1.0 means "edge."
Something like this:
color.a *= smoothstep(0.0, 2./thickness, 1.0-abs(vTexCoord.t));

JFreechart draw arc on chart

I have 2 questions
1)I am trying to draw an arc on an XYplot using the shape annotation. I used the XYLine annotation to draw a line and I want the arc to start where the line ends. I am having some issues with the parameters.I want the arc to have a height of 17, width 44, and start at the point(3.0, 17) of the plot(this is where the line ends). But the code below does not work. Can someone please tell me what is wrong with the code?
Arc2D.Double arc = new Arc2D.Double(3.0,
16.9,
44.0,
17.04,
180.0,
180.0,
Arc2D.OPEN
);
plot.addAnnotation(new XYShapeAnnotation(arc,
new BasicStroke(2.0f), Color.white));
XYLineAnnotation a1 = new XYLineAnnotation(3.0, 0.0, 3.0,
16.9, new BasicStroke(2.0f), Color.white);
2)How can I draw a similar figure on a polar plot?
Thanks
The critical thing about Arc2D is the bounding rectangle. To make the half-arc H units high, the bounds must be 2 * H units high.
AFAIK, PolarPlot does not support annotations.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Arc2D;
import java.util.Random;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYLineAnnotation;
import org.jfree.chart.annotations.XYShapeAnnotation;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/** #see http://stackoverflow.com/questions/6604211 */
public class ArcTest {
private static final Random r = new Random();
private static final double PI = 180d;
private static final int X = 3;
private static final int Y = 0;
private static final int W = 44;
private static final int H = 17;
public static void main(String[] args) {
JFreeChart chart = ChartFactory.createXYLineChart(
"ArcTest", "X", "Y", createDataset(),
PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = chart.getXYPlot();
XYLineAnnotation line = new XYLineAnnotation(
X, Y, X, H, new BasicStroke(2f), Color.blue);
plot.addAnnotation(line);
Arc2D.Double arc = new Arc2D.Double(
X, Y, W, 2 * H, PI, PI, Arc2D.OPEN);
plot.addAnnotation(new XYShapeAnnotation(arc,
new BasicStroke(2.0f), Color.blue));
ChartFrame frame = new ChartFrame("First", chart);
frame.pack();
frame.setVisible(true);
}
private static XYDataset createDataset() {
XYSeriesCollection result = new XYSeriesCollection();
XYSeries series = new XYSeries("ArcTest");
series.add(0, 0);
series.add(W, W);
result.addSeries(series);
return result;
}
}