如何在Java swing中构建点击组件?

时间:2011-08-30 12:23:25

标签: java swing mouseevent jcomponent

我构建了一个只显示一行的自定义组件。该线条从左上角到右下角绘制为paint方法中的Line2D。背景是透明的。我扩展了JComponent。当鼠标指针位于最大值时,这些线条组件可拖动并更改其线条颜色。距绘制线15个像素。 但是如果我将多个这些组件添加到另一个扩展JPanel的自定义组件中,它们有时会重叠。我想实现,如果鼠标指针距离线超过15个像素,鼠标事件应该通过组件落下。如何让它落空是我的问题。 这甚至可能吗?

提前致谢!

5 个答案:

答案 0 :(得分:3)

  

如果鼠标指针超过15像素,我想实现它   远离线条,鼠标事件应该通过组件落下。

如果您的子组件具有鼠标侦听器,则它将拦截在其上发生的每个鼠标事件。如果要将MouseEvent转发到父Component,则应手动执行。例如,您可以实现扩展MouseAdapter的自定义鼠标侦听器:

public class yourMouseListener extends MouseAdapter{

    //this will be called when mouse is pressed on the component
    public void mousePressed(MouseEvent me) { 
         if (/*do your controls to decide if you want to propagate the event*/){
              Component child = me.getComponent();
              Component parent = child.getParent();

              //transform the mouse coordinate to be relative to the parent component:
              int deltax = child.getX() + me.getX();
              int deltay = child.getY() + me.getY();

              //build new mouse event:
              MouseEvent parentMouseEvent =new MouseEvent(parent, MouseEvent.MOUSE_PRESSED, me.getWhen(), me.getModifiers(),deltax, deltay, me.getClickCount(), false) 
              //dispatch it to the parent component
              parent.dispatchEvent( parentMouseEvent);
         }
    }
}

答案 1 :(得分:2)

我触摸Swing已经有一段时间了,但我认为您需要在父组件中处理鼠标事件,然后使用行循环遍历子组件并确定它们中的哪一个应该处理事件(嗯,决定逻辑应该仍然保留在行组件中,但是父将显式调用该逻辑,直到其中一个组件接受事件)。

答案 2 :(得分:2)

对于我在大学的最后一年项目,我做了一个白板程序并遇到了同样的问题。对于用户绘制的每个形状,我创建了一个JComponent,它在绘制矩形时很好,但使用自由形式线工具则更难。

我最终修复它的方法是完全取消JComponents。我有一个JPanel,它持有Vector(我认为)自定义Shape对象。每个物体都有自己的坐标和线条厚度等。当用户单击板时,JPanel上的鼠标侦听器触发并遍历每个Shape,在每个Shape上调用一个contains(int x,int y)方法(x和y是事件的坐标)。因为Shapes在绘制时被添加到Vector中,所以我知道返回true的最后一个是最顶层的Shape。

这是我用于直线包含方法的内容。数学可能有点不确定,但它对我有用。

public boolean contains(int x, int y) {

    // Check if line is a point
    if(posX == endX && posY == endY){
        if(Math.abs(posY - y) <= lineThickness / 2 && Math.abs(posX - x) <= lineThickness / 2)
            return true;
        else
            return false;
    }

    int x1, x2, y1, y2;

    if(posX < endX){
        x1 = posX;
        y1 = posY;
        x2 = endX;
        y2 = endY;
    }
    else{
        x1 = endX;
        y1 = endY;
        x2 = posX;
        y2 = posY;
    }


    /**** USING MATRIX TRANSFORMATIONS ****/

    double r_numerator = (x-x1)*(x2-x1) + (y-y1)*(y2-y1);
    double r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
    double r = r_numerator / r_denomenator;

    // s is the position of the perpendicular projection of the point along
    // the line: s < 0 = point is left of the line; s > 0 = point is right of
    // the line; s = 0 = the point is along the line
    double s =  ((y1-y)*(x2-x1)-(x1-x)*(y2-y1) ) / r_denomenator;

    double distance = Math.abs(s)*Math.sqrt(r_denomenator);

    // Point is along the length of the line
    if ( (r >= 0) && (r <= 1) )
    {
            if(Math.abs(distance) <= lineThickness / 2){
                return true;
            }
            else
                return false;
    }
    // else point is at one end of the line
    else{
        double dist1 = (x-x1)*(x-x1) + (y-y1)*(y-y1); // distance to start of line
        double dist2 = (x-x2)*(x-x2) + (y-y2)*(y-y2); // distance to end of line
        if (dist1 < dist2){
            distance = Math.sqrt(dist1);
        }
        else{
            distance = Math.sqrt(dist2);
        }
        if(distance <= lineThickness / 2){
            return true;
        }
        else
            return false;
    }
    /**** END USING MATRIX TRANSFORMATIONS****/

}

posX和posY组成行开头的坐标,endX和endY是行的结尾。如果单击位于线条中心的lineThickness / 2范围内,则返回true,否则您必须沿着线条的正中间单击。

绘制形状是将JPanel的Graphics对象传递给每个Shape并使用它进行绘制的情况。

答案 3 :(得分:1)

我认为最简单的方法是捕捉事件并致电parent.processEvent()。因此,您的组件对于事件将是透明的,因为它会将它们传播到父级。

答案 4 :(得分:0)

我正在努力解决这类问题,并尝试了所有与父母和玻璃窗的东西,直到我意识到覆盖contains方法正是你想要的。因为当父母点燃某种getcomponent你的'Line'会回复它:'不,它不是我,我不在那里!'并且循环将检查其他组件。 此外,当您需要为可拖动对象设置复杂深度时,可以使用JLayeredPane后代。