首页 > 解决方案 > 如何限制 JavaFx8 Polygon-Triangle 的 MouseEvents:仅触发三角形本身,而不是三角形布局矩形边界?

问题描述

我使用 Polygon 对象创建了一个三角形,以及允许在屏幕周围鼠标拖动三角形的 onMousePressed、Dragged、Release 事件。在我创建的 JavaFX 应用程序(用于独立笔记本电脑)游戏中运行良好。

问题是,我希望 Triangle MouseEvents 仅在三角形形状边界内触发,而不是在三角形之外触发。目前,事件似乎在 Polygon-Triangle 不可见 RECTANGLE 布局范围内的任何地方触发(即嵌入/包围三角形的不可见矩形)。此行为允许通过以下方式拖动三角形:1) 光标在三角形的外部和 2) 光标在 Polygon-Triangle 不可见矩形边界内的任何位置。

这种行为通过以下方式使用户感到困惑:1) 无意中拖动三角形,2) 阻止其他游戏片段的事件(被不可见的三角形矩形边界重叠。)使它们无法播放,直到三角形被拖出。

我已经使用 Ellipse 对象和“setPickOnBounds(true);”属性完成了对 Shape 的 MouseEvent 限制。似乎与 Polygon 对象不一样。


我在 stackOverflow.com 上进行了检查,我能找到的解决此问题的最接近的文章如下,它没有解决 MouseEvent 在 Shapes 内部/外部触发的问题。

StackOverflow.com: 1. 如何平滑拖动 JavaFX 多边形? 如何平滑拖动 JavaFX 多边形? 文章未涉及形状可点击区域。

  1. Android 自定义形状按钮 Android 自定义形状按钮 是 5 岁和 Android 特定的,javaFX8 和多边形是否有更有效的方法?此外,我的三角形尺寸是动态的,可以与嵌入的用户格式化 LabelText 的大小相匹配。

    因此,要使用三角形图像文件,需要数百个三角形文件才能获得最佳选择。

请帮助...谢谢。迈克尔

我创建三角形的代码:

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);
    }
}

. . . 这是来自另一个函数,计算和设置三角形:

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

标签: javafx-8mouseeventpolygonboundsclickable

解决方案


更正我的初始描述:我说 Ellipse 对象 bounds-rectangle 没有捕获底层/重叠对象的鼠标事件。错误的。它们确实存在与三角形相同的问题(我现在假设,所有 javaFX Shape 对象子对象也是如此。)

***********我的肮脏解决方案************* 我找到了一个肮脏但大多数可行的解决方案来解决这个问题,显然是由所有 javaFX Shape 对象子级产生的。问题是由 Shape 对象 bounds-rectangle 捕获底层/重叠对象的鼠标事件引起的......我无法对鼠标事件触发进行编码以仅限制形状,同时仍然使重叠对象可点击:

1)内部三角形onMousedPressed事件处理程序:检查用户是否点击了OutsideTriangle-but-InsideTriangleRectBounds:(使用重心风格算法......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) 如果高于 TRUE,则将 isClickedOutsideTriangle 标志设置为 TRUE,然后退出/返回事件处理程序而不消耗事件。

3) TEST isClickedOutsideTriangle 标志位于内部 onMousedDragged 事件处理程序的开头。如果为真,则从处理程序退出/返回,而不使用消耗()。

4) 在 Triangle onMousedReleased 事件处理程序内部: - 测试 Triangle bounds-rectangle 是否与任何游戏板元素相交。如果是:[为了保留用户指定的游戏部件 zIndex] - 保存所有元素 zIndex 值。-SORT Element zIndex values Ascending -SET sorted value Elements toFront() [这现在允许所有元素都是可点击的]

5) 如果 isClickedOutsideTriangle 标志为 TRUE,则重置为 FALSE。


警告:这个解决方案的一个不幸的副作用是:用户永远不会被允许让三角形重叠任何其他游戏元素,但其他游戏元素可以重叠三角形!

我仍在寻找使用 javaFX 对象属性/方法的更简单的解决方案,这将允许 1)Shape-object bounds-rectangle 底层元素的完全可点击性和 2)Shapes 的动态大小,由游戏期间的用户格式化决定???? ?


推荐阅读