0

I have created a Triangle using the Polygon object, along with onMousePressed, Dragged, Released events that allow the Triangle to be MouseDragged around the screen. Works fine in the JavaFX Application (for standalone Laptop) game I have created.

The problem is, I want the Triangle MouseEvents to fire only WITHIN the Triangle shape boundary, NOT outside the Triangle. Currently, Events seem to be firing anywhere within the Polygon-Triangle non-visible RECTANGLE layout bounds (ie the non-visible rectangle that embeds/surrounds the Triangle). This behavior allows the Triangle to be dragged with: 1) the cursor OUTSIDE of the Triangle & 2) the cursor ANYWHERE within the Polygon-Triangle non-visible rectangle bounds.

This behavior confuses the User by: 1) Unintentionally dragging the Triangle, 2) Blocking events of other game pieces (that are overlapped by the non-visible Triangle rectangle bounds.) making them unplayable, until Triangle is dragged out of the way.

I have accomplished this MouseEvent Restriction to Shape using the Ellipse object & the "setPickOnBounds(true); " property. Doesn't seem to work the same with Polygon objects.


I have checked on stackOverflow.com, & the closest article addressing this issue, that I could find, is the following, it does not address MouseEvent firing inside/outside Shapes.

StackOverflow.com: 1. How to smooth drag a JavaFX polygon? How to smooth drag a JavaFX polygon? Article did not address Shape Clickable area.

  1. Android Custom Shape Button Android Custom Shape Button Is 5 years old & Android specific, Is there a more efficient way with javaFX8 & Polygons? Also, my Triangle dimensions are dynamic, claculated to match the size of embeded User formated LabelText.

    So to use a Triangle image file, would required hundreds of Triangle files, for a best fit option.

Please HELP... Thanks. Michael

My code for creating Triangle:

public static class StrategySelfNote_Element extends Group {
    public Polygon triangle;
    public Label label;

    public StrategySelfNote_Element(int id) {

        // Triangle ********************************************************************************
        triangle = new Polygon();
        triangle.setId(Integer.toString(id)+";StrategySelfNote");         
        triangle.setFill(Color.AQUA);
        triangle.setCursor(Cursor.HAND);
        triangle.setVisible(false);
        triangle.setLayoutX(0);
        triangle.setLayoutY(0);
        triangle.setCache(true);

        // NOTE: This allowed Ellipse to be Dragged by MouseEvent, else only by Label (not sure if required w/Triangle???)
        triangle.setPickOnBounds(true); 


        // Label **********************************************************************************
        label = new Label();
        label.setId(Integer.toString(id)+";StrategySelfNote");         
        label.setFont(Font.font  ("Calibri", FontWeight.BOLD, IntroQuestions.sizeFont_strategySelfNotes));//28
        label.setWrapText(true);
        label.setMaxWidth(MAX_WIDTH_STRATEGY_SELF_NOTE); // To Prevent HUGE TextRectangle
        label.setMaxHeight(MAX_HEIGHT_STRATEGY_SELF_NOTE);
        label.setAlignment(Pos.TOP_LEFT);
        label.setStyle("-fx-background-color: aqua;"); //  -fx-background-color: AQUA; // light-yellow
        //-------------
        label.setCursor(Cursor.HAND);
        label.setVisible(false);
        label.setLayoutX(0); //debug: TRY 0 like before---to FIX When Dragging to 3/4 Quad, FREEZES & PANs scrlPane !!!
        label.setLayoutY(0);
        label.setCache(true);
        //-------------

        getChildren().addAll(triangle, label);

        //------------- paneElement
        this.setLayoutX(0.0); //10-26
        this.setLayoutY(0.0);
        this.setId(Integer.toString(id)+";StrategySelfNote");

        this.setPickOnBounds(true); // NOTE: This allows Polygon to be Dragged by MouseEvent, else only by Label

        this.setVisible(false);
        this.setCache(true);
        //-----
        this.setOnMousePressed(boardStrategySelfNote_OnMousePressedEventHandler);
        this.setOnMouseDragged(boardStrategySelfNote_OnMouseDraggedEventHandler);
        this.setOnMouseReleased(boardStrategySelfNote_OnMouseReleasedEventHandler);
        this.addEventFilter(InputEvent.ANY, boardStrategySelfNote_OnMouseFilterEventHandler);
    }
}

. . . This is from another function, to Calculate & Set Triangle:

      llStrategySelfNotes.get(strategySelfNote_id-1).groupStrategySelfNote_Element.triangle.getPoints().addAll(
            triBottomLeftX, triBottomLeftY,
            triBottomRightX, triBottomRightY,
            triTopX, triTopY);
cUcMe
  • 1
  • 3

1 Answers1

0

CORRECTION TO MY INITIAL DESCRIPTION: I said that Ellipse objects bounds-rectangle did not catch mouse events of underlying/overlapped objects. WRONG. They DO & they present same problem as Triangles (I assume now, as do all javaFX Shape object children.)

***********My Dirty Solution************* I have found a Dirty but mostly workable solution to this problem, apparently produced by all javaFX Shape object children. The problem is caused by the Shape object bounds-rectangle catching mouse events of underlying/overlapped objects... I am unable to Code mouse event firing to restrict ONLY over shape, while still having overlapped objects be Clickable:

1) Inside Triangle onMousedPressed event handler: CHECK if User Clicked OutsideTriangle-but-InsideTriangleRectBounds: (use Barycentric style algorythm... many one's available on stackOverflow)

static boolean isInside(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3) {
    double L1 = (x-x1)*(y3-y1) - (x3-x1)*(y-y1), 
           L2 = (x-x2)*(y1-y2) - (x1-x2)*(y-y2), 
           L3 = (x-x3)*(y2-y3) - (x2-x3)*(y-y3);
    return (L1>0 && L2>0  && L3>0) || (L1<0 && L2<0 && L3<0);
}    

isInTriangle = isInside (t.getX(), t.getY(),
                                            triBottomLeftX, triBottomLeftY,
                                        triBottomRightX, triBottomRightY,
                                    triTopX, triTopY);            

2) If above TRUE, SET isClickedOutsideTriangle flag to TRUE, then exit/return event handler WITHOUT consuming event.

3) TEST isClickedOutsideTriangle flag at beginning of inside onMousedDragged event handler. If true, exit/return from handler, without consume().

4) Inside Triangle onMousedReleased event handler: -TEST if Triangle bounds-rectangle Intersects ANY game board elements. If yes: [in order to Preserve User specified zIndex of game pieces] -SAVE all Element zIndex values. -SORT Element zIndex values Ascending -SET sorted value Elements toFront() [this now allows all Elements to be Clickable]

5) If isClickedOutsideTriangle flag is TRUE, reset to FALSE.


WARNING: An unfortunate side-effect of this solution is: Users will never be allowed to have Triangles Overlap any other game elements, but other game elements can overlap Triangles !

I am still looking for a simpler solution using javaFX object properties/methods, that will allow 1) full Clickability of elements underlying Shape-object bounds-rectangle & 2) dynamic sizing of Shapes, determined by User formating during game play ?????

cUcMe
  • 1
  • 3