I'm creating circles of size 5 with something like Circle c = new Circle(x, y, 5);. Then I do c.setOnMousePressed(mousePressedEventHandler); but I've got a problem here : my circle is too small and it's easy to miss it. I would like to keep this size so is there a way to increase the hitbox of a circle without doing something like creating an invisible circle bigger and then set the listner on it ?
Increase the hit area by adding a transparent stroke to the circles.
Note: To actually use hit boxes you need to set the pickOnBounds property to true.
private static Circle createCircle(double x, double y, double radius, double hitRadius) {
Circle circle = new Circle(x, y, radius, Color.BLACK);
circle.setStrokeType(StrokeType.OUTSIDE);
circle.setStroke(Color.TRANSPARENT);
circle.setStrokeWidth((hitRadius < radius) ? 0 : (hitRadius - radius));
return circle;
}
#Override
public void start(Stage primaryStage) {
Pane root = new Pane();
Circle circle1 = createCircle(100, 100, 5, 20);
Circle circle2 = createCircle(150, 150, 5, 20);
circle1.setOnMouseClicked(evt -> System.out.println("clicked 1"));
circle2.setOnMouseClicked(evt -> System.out.println("clicked 2"));
root.getChildren().addAll(
circle1,
circle2
);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
Related
So for example, to draw a regular dodecagon on Javafx, you have to know all the coordinates of 12 points. But I was wondering if there's any way to draw it without knowing the coordinates of the points(but merely knowing that there are 12 sides for that polygon) so that if the user types '6', then it draws a regular hexagon and if the user types '12', it draws a regular dodecagon.
No, it's impossible to draw a polygon without knowing the the coordinates of the corners. How would such a object be rendered without the rendering engine knowing the coordinates of the vertices it needs to render?
You can of course calculate the coordinates of the points of a regular polygon given a center point, the distance of the corners from the center and the angle of one of the corners from the center point by convertion polar coordinates to cartesian coordinates:
private static void setPolygonSides(Polygon polygon, double centerX, double centerY, double radius, int sides) {
polygon.getPoints().clear();
final double angleStep = Math.PI * 2 / sides;
double angle = 0; // assumes one point is located directly beneat the center point
for (int i = 0; i < sides; i++, angle += angleStep) {
polygon.getPoints().addAll(
Math.sin(angle) * radius + centerX, // x coordinate of the corner
Math.cos(angle) * radius + centerY // y coordinate of the corner
);
}
}
#Override
public void start(Stage primaryStage) {
Spinner<Integer> spinner = new Spinner(3, Integer.MAX_VALUE, 3);
Polygon polygon = new Polygon();
setPolygonSides(polygon, 200, 200, 150, spinner.getValue());
spinner.valueProperty().addListener((observable, oldValue, newValue) -> {
setPolygonSides(polygon, 200, 200, 150, spinner.getValue());
});
StackPane stackPane = new StackPane(polygon);
stackPane.setPrefSize(400, 400);
HBox root = new HBox(spinner, stackPane);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
I've been trying to find a way to do this online, but I haven't been able to find anything.
I want to draw an "inverse circle" with the JavaFX GraphicsContext.
These images show what I want.
Original:
With "Inverted Circle" (What I want to draw):
In an image editor I can just erase the circle area in the new layer... I don't see any functions that would do that in GraphicsContext.
I'd need to be able to choose the center point and radius of this "circle".
Thanks!
I am not very sure of directly using GraphicsContext, but you can do it using Blending.
ImageView image; // Your image
Circle mask = new Circle();
Group g = new Group();
g.setBlendMode(BlendMode.SRC_ATOP);
g.getChildren.add(image);
g.getChildren.add(mask);
Construct a circular path and use it as clip when drawing the image:
#Override
public void start(Stage primaryStage) {
Image image = new Image("https://i.stack.imgur.com/zEoW1.jpg");
double w = image.getWidth();
double h = image.getHeight();
Canvas canvas = new Canvas(w, h);
GraphicsContext gc = canvas.getGraphicsContext2D();
// draw background
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, w, h);
double r = Math.min(h, w) * 2 / 5;
double cx = w / 2;
double cy = h / 2;
// create circular path
gc.beginPath();
gc.moveTo(cx - r, cy); // to first point on the circle
gc.arc(cx, cy, r, r, 180, 360);
gc.closePath();
gc.clip();
gc.drawImage(image, 0, 0);
StackPane root = new StackPane();
root.getChildren().add(canvas);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
Hi I want to rotate text (-40)/ And I Have problem when a text is short this start on diffrent hegh I Want to that text start when I mark. This punkt I do like this
for(int i=0; i<=Config.busSizeInView; i++){
gc.drawImage(busStop, 10+i*Config.xSize/Config.busSizeInView, Config.ySize -100, 20, 20);
}
I do this
for(int i =0 ;i<Config.busSizeInView;i++){
nameBusStop.add(new Text("Konstytucji 3 Maja - Dworzec PKS 02"));
}
for(int i=0 ; i<nameBusStop.size(); i++){
nameBusStop.get(i).setRotate(-40);
nameBusStop.get(i).setText(Main3.listBusStops.get(i).getName());
}
for(int i =0 ; i<nameBusStop.size(); i++){
nameBusStop.get(i).relocate(i*Config.xSize/Config.busSizeInView-Config.padding-10, Config.ySize - Config.ySize/6 - Config.padding*3);
}
line.getChildren().addAll(canvas,txtPane);
Pane txtPane = new Pane();
for(Text text : nameBusStop){
text.setFont(Font.font ("Verdana", 20));
txtPane.getChildren().add(text);
}
line.getChildren().addAll(canvas,txtPane);
When a text is longer
You could use the Canvas to draw the strings too:
public static void drawStop(double x, double y, String text, GraphicsContext gc) {
gc.save();
gc.translate(x, y);
gc.fillRect(-5, 0, 10, 10);
gc.rotate(-40);
gc.fillText(text, 5, 0);
gc.restore();
}
#Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(900, 400);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFont(Font.font ("Verdana", 20));
drawStop(100, 380, "Stop 1", gc);
drawStop(200, 380, "Stop 2", gc);
drawStop(500, 380, "Stop 3 Stop 3 Stop 3 Stop 3 Stop 3 Stop 3", gc);
Scene scene = new Scene(new Group(canvas));
primaryStage.setScene(scene);
primaryStage.show();
}
Alternatively don't use a StackPane which centers the children. Also don't use the rotate property, since it rotates around the center of a Node. Use a Rotate transform instead to rotate around (0, 0):
public static void drawStop(double x, double y, String text, GraphicsContext gc, Pane pane) {
gc.fillRect(x-5, y, 10, 10);
Text textNode = new Text(text);
textNode.setFont(Font.font ("Verdana", 20));
textNode.setBoundsType(TextBoundsType.VISUAL);
textNode.relocate(x, y-15);
textNode.getTransforms().add(new Rotate(-40));
pane.getChildren().add(textNode);
}
#Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
Canvas canvas = new Canvas(900, 400);
pane.getChildren().add(canvas);
GraphicsContext gc = canvas.getGraphicsContext2D();
drawStop(100, 380, "Stop 1", gc, pane);
drawStop(200, 380, "Stop 2", gc, pane);
drawStop(500, 380, "Stop 3 Stop 3 Stop 3 Stop 3 Stop 3 Stop 3", gc, pane);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
I can not understand how moveTo method work in javafx. here is my example
I have a GridPane that consist of 4 columns and 1 row. All the columns h has a StackPane and the last Stackpane also has an empty label.
public class PathTransitionTExample extends Application {
StackPane pane;
GridPane grid;
Label label;
Scene scene;
#Override
public void start(Stage primaryStage) {
label = new Label();
label.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
grid = new GridPane();
grid.getStyleClass().add("gridPane");
for (int x = 0; x < 4; x++) {
grid.add(pane = new StackPane(), x, 0);
pane.setPrefSize(50, 50);
pane.getStyleClass().add("stackPane");
}
pane = (StackPane) grid.getChildren().get(3);
pane.getChildren().add(label);
scene = new Scene(grid, 260, 50);
scene.getStylesheets().add(PathTransitionTest.class.getResource("pathCSS.css").toExternalForm());
scene.setOnMouseClicked(me -> pathTransition());
primaryStage.setTitle("Path Transition");
primaryStage.setScene(scene);
primaryStage.show();
}
//pathCSS.css
.gridPane{
-fx-background-color: red;
-fx-hGap: 20;
}
.stackPane{
-fx-background-color: orange;
}
.label {
-fx-background-color: blue;
}
I want to move the label in the grid pane from 0.3 to 0.0 however when I am trying to do that the whole transition slips.
private void pathTransition() {
//the Coordinates of the label
double oldMinX = grid.getChildren().get(3).getLayoutX();
double oldMinY = grid.getChildren().get(3).getLayoutY();
//the coordinates of the stack pane where i want the label move
double newMinX = grid.getChildren().get(1).getLayoutX();
double newMinY = grid.getChildren().get(1).getLayoutY();
Path path = new Path();
path.getElements().add(new MoveTo(oldMinX, oldMinY ));
path.getElements().add(new LineTo(newMinX,newMinY ));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(new Duration(500));
pathTransition.setPath(path);
pathTransition.setNode(label);
pathTransition.play();
}
If I change the arguments of MoveTo and LineTo by the following I can achieve the animation I want but I cant understand why. :\
double oldMinX = grid.getChildren().get(3).getLayoutX() -185;
double oldMinY = grid.getChildren().get(3).getLayoutY()+ grid.getChildren().get(3).getBoundsInLocal().getHeight()/2 ;
double newMinX = grid.getChildren().get(1).getLayoutX()-255 ;
double newMinY = grid.getChildren().get(1).getLayoutY() + grid.getChildren().get(0).getBoundsInLocal().getHeight()/2 ;
I guess It is because transitions use different coordinate systems than scenes but I cant really find anything that explains well :( Could someone give me some hints how It is working?
Thank you so much in advance.
I realized that i shouldn't use GridPane. If i do it without using containers the transition is working fine.
So, I'm using LibGdx and trying to use their Rectangle class as a bounds for button pressing onn the touch screen. It works perfectly on a 1:1 scale, but when I put the game on my Phone (With a smaller screen) than the images get scaled and drawn properly, but the Rectangles don't. So I tried keeping my Rectangles at their normal scale, and "upscaling" the touch screen's XY Coords, but I guess I'm not doing that right, cause it doesn't work.
optionsMenu = new Vector<Rectangle>();
optionsMenu.add(new Rectangle(100 + (120 * 0), 100, 100, 100));
optionsMenu.add(new Rectangle(100 + (120 * 1), 100, 100, 100));
optionsMenu.add(new Rectangle(100 + (120 * 2), 100, 100, 100));
optionsMenu.add(new Rectangle(100 + (120 * 3), 100, 100, 100));
That's how i'm initalizing my bounding Rectangles.
This is how I'm initalizing my camera:
camera = new OrthographicCamera();
camera.setToOrtho(true, 800, 480);
This is how I'm drawing my buttons:
spriteBatch.draw(buttonImage, optionsMenu.get(2).bounds.getX(),
optionsMenu.get(2).bounds.getY(), optionsMenu.get(2).bounds.getWidth(),
optionsMenu.get(2).bounds.getHeight(), 0, 0, buttonImage.getWidth(),
buttonImage.getHeight(), false, true);
And this is how I do my touch screen logic:
public boolean tap(float x, float y, int count, int button) {
Vector3 temp = new Vector3(x, y, 0);
camera.unproject(temp);
float scalePos = (int) ((float) Gdx.graphics.getWidth()/800.0f);
temp.x = temp.x * scalePos;
temp.y = temp.y * scalePos;
if(optionsMenu.get(0).bounds.contains(temp.x, temp.y)){
//do sutff
}
else if(optionsMenu.get(1).bounds.contains(temp.x, temp.y)){
//do other stuff
}
return false;
}
A few days ago I ran into the same problem. This is what I did to solve it:
If you are using a viewport, then you should add that data to the camera.unproject call, to make sure that the viewport is being taken into account.
For example:
camera.unproject(lastTouch,viewport.x,viewport.y,viewport.width,viewport.height);
To debug the rectangle bounds and the touch position, I used this method to draw them into the screen:
private static ShapeRenderer debugShapeRenderer = new ShapeRenderer();
public static void showDebugBoundingBoxes(List<Rectangle> boundingBoxes) {
debugShapeRenderer.begin(ShapeType.Line); // make sure to end the spritebatch before you call this line
debugShapeRenderer.setColor(Color.BLUE);
for (Rectangle rect : boundingBoxes) {
debugShapeRenderer.rect(rect.x, rect.y, rect.width, rect.height);
}
debugShapeRenderer.end();
}