RayanFar
RayanFar

Reputation: 587

why onMouseClick doesnt work in javafx circle shape?

I want to click on one of three button on title of my internal window to change its color to black. but it some times works and sometimes does`nt work. please look at my code an tell me whats wrong with it!?

I used javac 1.8u20 to compile and jre 1.9 to run... if we use to or three layer of Pane inside of each other how the events handle? is there problem?

package core.windowManager;

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Screen;

import static javafx.scene.paint.Color.rgb;

/**
 * Created by yn on 22/08/17.
 * just declare a win not more ...
 */
public class win {

/**
 * where we add the win to it in scene
 */
private final AnchorPane root;
/**
 * just the title and a hashCode from instance  will be the win ID
 */
private final String winId;
/**
 * win pane contains title and content pane
 */
private final AnchorPane winPane = new AnchorPane();
/**
 * title pane to add title label and some three [close-min-max] buttons maybe...
 */
private final AnchorPane titlePane = new AnchorPane();
/**
 * where the content goes there ...
 */
private final AnchorPane content = new AnchorPane();

/**
 * win title pane height
 */
private final int winTitlePaneH = 30;
/**
 * three close-min-max buttons
 */
private final Circle closeShape = new Circle();
private final Circle minShape = new Circle();
private final Circle maxShape = new Circle();


/**
 * initialize the win class with some important params
 *
 * @param root  //where the win add to scene
 * @param title // and String ID make by title+hashCode and used in windowManager
 * @param winW  //win width
 * @param winH  // win height
 */
public win(AnchorPane root, String title, int winW, int winH) {

    //init some final vars
    this.root = root;
    this.winId = title + "--" + this.hashCode();

    // make the winPane
    winPane.setEffect(new DropShadow(20, rgb(0, 0, 0, 0.9)));
    winPane.setPrefSize(winW, winH);
    winPane.setStyle("-fx-background-color: #abcdef");
    // put winPane center of scene
    double screenW = Screen.getPrimary().getVisualBounds().getWidth();
    double screenH = Screen.getPrimary().getVisualBounds().getHeight();
    double deltaW = (screenW - winW) / 2;
    double deltaH = (screenH - winH) / 2;
    winPane.setLayoutX(deltaW);
    winPane.setLayoutY(deltaH);
    // put it to top on click
    winPane.setOnMouseClicked(e -> {
        winPane.toFront();
    });

    //make title and top of window ...
    titlePane.setPrefHeight(winTitlePaneH);
    AnchorPane.setTopAnchor(titlePane, 0.0);
    AnchorPane.setLeftAnchor(titlePane, 0.0);
    AnchorPane.setRightAnchor(titlePane, 0.0);

    // make winPane draggable by titlePane
    makeDragable(titlePane);
    makeResizable(50);

    // add close and min buttons to title pane
    closeShape.setRadius(winTitlePaneH / 3);
    closeShape.setFill(Color.RED); //red-yellow-green
    closeShape.setOnMouseClicked(e -> {
        closeShape.setFill(Color.BLACK);
        e.consume();
    });

    //add min button to title pane
    minShape.setRadius(winTitlePaneH / 3);
    minShape.setFill(Color.YELLOW); //red-yellow-green
    minShape.setOnMouseClicked(e -> {
        minShape.setFill(Color.BLACK);
    });

    // add max button to title pane
    maxShape.setRadius(winTitlePaneH / 3);
    maxShape.setFill(Color.GREEN); //red-yellow-green
    maxShape.setOnMouseClicked(e -> {
        maxShape.setFill(Color.BLACK);

    });

    HBox bb = new HBox();
    //bb.setBackground(new Background(new BackgroundFill(Color.BLACK, null, Insets.EMPTY)));
    AnchorPane.setLeftAnchor(bb, 0d);
    AnchorPane.setTopAnchor(bb, winTitlePaneH / 4.5);
    AnchorPane.setBottomAnchor(bb, 0d);
    bb.getChildren().addAll(closeShape, minShape, maxShape);
    titlePane.getChildren().addAll(bb);


    // add a label to show title
    Label titleL = new Label(title);
    titleL.setTextFill(Color.BLACK);
    titleL.setAlignment(Pos.BASELINE_CENTER);
    AnchorPane.setTopAnchor(titleL, 5.0);
    AnchorPane.setLeftAnchor(titleL, 0.0);
    AnchorPane.setRightAnchor(titleL, 0.0);
    titlePane.getChildren().add(titleL);


    titlePane.setBackground(new Background(new BackgroundFill(Color.web("#E2E0E2"), CornerRadii.EMPTY, Insets.EMPTY)));

    winPane.getChildren().add(titlePane);
    root.getChildren().add(winPane);


}


/**
 * titlePane to drag and win move behavior
 *
 * @param what
 */
public void makeDragable(Node what) {
    final Delta dragDelta = new Delta();

    what.setOnMousePressed(mouseEvent -> {
        dragDelta.x = winPane.getLayoutX() - mouseEvent.getScreenX();
        dragDelta.y = winPane.getLayoutY() - mouseEvent.getScreenY();
        //also bring to front when moving
        winPane.toFront();

    });

    what.setOnMouseDragged(mouseEvent -> {
        winPane.setLayoutX(mouseEvent.getScreenX() + dragDelta.x);
        winPane.setLayoutY(mouseEvent.getScreenY() + dragDelta.y);

    });
}

//current state
private boolean RESIZE_BOTTOM;
private boolean RESIZE_RIGHT;

public void makeResizable(double mouseBorderWidth) {
    winPane.setOnMouseMoved(mouseEvent -> {
        //local window's coordiantes
        double mouseX = mouseEvent.getX();
        double mouseY = mouseEvent.getY();
        //window size
        double width = winPane.boundsInLocalProperty().get().getWidth();
        double height = winPane.boundsInLocalProperty().get().getHeight();
        //if we on the edge, change state and cursor
        if (Math.abs(mouseX - width) < mouseBorderWidth
                && Math.abs(mouseY - height) < mouseBorderWidth) {
            RESIZE_RIGHT = true;
            RESIZE_BOTTOM = true;
            winPane.setCursor(Cursor.NW_RESIZE);
        } else {
            RESIZE_BOTTOM = false;
            RESIZE_RIGHT = false;
            winPane.setCursor(Cursor.DEFAULT);
        }

    });
    winPane.setOnMouseDragged(mouseEvent -> {
        //resize root
        Region region = (Region) winPane;
        //resize logic depends on state
        if (RESIZE_BOTTOM && RESIZE_RIGHT) {
            region.setPrefSize(mouseEvent.getX(), mouseEvent.getY());
        } else if (RESIZE_RIGHT) {
            region.setPrefWidth(mouseEvent.getX());
        } else if (RESIZE_BOTTOM) {
            region.setPrefHeight(mouseEvent.getY());
        }
    });
}

//just for encapsulation
private static class Delta {
    double x, y;
}

}

Upvotes: 0

Views: 909

Answers (2)

vl4d1m1r4
vl4d1m1r4

Reputation: 1781

Mouse click works perfectly fine on Circle in JavaFX. The problem with your code is that the label you add for the title is on top of your circles and catches the mouse clicks. You can only click the circles on the very bottom which made you think that it works "sometimes". Check the image here:

Inspected with ScenicView

So you can solve it by making the label mouse transparent with:

titleL.setMouseTransparent(true);

or adding first the label and then the HBox with the circles.

For this kind of problems ScenicView comes really handy tool.

Upvotes: 2

RayanFar
RayanFar

Reputation: 587

I use a HBox to group and layout the three buttons [close min max] and then toFront() it. and they goes over title pane and now events work correctly...

Upvotes: 0

Related Questions