4

線だけを表示するカスタムコンポーネントを作成しました。線は、ペイント方法でLine2Dとして左上隅から右下隅に描画されます。背景は透明です。JComponentを拡張しました。これらの線の構成要素はドラッグ可能であり、マウスポインタが最大にあるときに線の色を変更します。描画された線から15ピクセル離れています。しかし、これらのコンポーネントの複数をJPanelを拡張する別のカスタムコンポーネントに追加すると、それらが重複することがあります。マウスポインタが線から15ピクセル以上離れている場合、マウスイベントがコンポーネントを通過するように実装したいと思います。それをどのように通過させるかが私の問題です。それも可能ですか?

前もって感謝します!

4

5 に答える 5

3

マウスポインタが線から15ピクセル以上離れている場合、マウスイベントがコンポーネントを通過するように実装したいと思います。

子コンポーネントにマウスリスナーがある場合、そのコンポーネントで発生するすべてのマウスイベントをインターセプトします。MouseEventを親コンポーネントに転送する場合は、手動で行う必要があります。たとえば、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);
         }
    }
}
于 2011-08-30T13:56:07.390 に答える
2

Swingに触れてからしばらく経ちますが、親コンポーネントでマウスイベントを処理してから、子コンポーネントを線でループして、イベントを処理するコンポーネントを決定する必要があると思います(決定のロジックまだラインコンポーネントに残っている必要がありますが、コンポーネントの1つがイベントを受け取るまで、親はそのロジックを明示的に呼び出します)。

于 2011-08-30T14:06:56.697 に答える
2

大学での最終年度のプロジェクトでは、ホワイトボードプログラムを実行しましたが、同じ問題が発生しました。ユーザーがボード上に描いた形状ごとに、JComponentを作成しました。これは、長方形を描いているときは問題ありませんでしたが、自由形式の線ツールではさらに困難でした。

最終的に修正した方法は、JComponentsを完全に廃止することでした。カスタムShapeオブジェクトのVector(私は思う)を保持するJPanelがありました。各オブジェクトは、独自の座標や線の太さなどを保持していました。ユーザーがボードをクリックすると、JPanelのマウスリスナーが起動し、各Shapeを通過して、各Shapeでcontains(int x、int y)メソッドを呼び出しました(xとyはイベントの座標です)。シェイプは描画時にベクターに追加されたため、trueを返す最後のシェイプが一番上のシェイプであることがわかりました。

これは私が直線containsメソッドに使用したものです。数学は少し難しいかもしれませんが、それは私にとってはうまくいきました。

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を返しました。そうでない場合は、線の真ん中に沿って右クリックする必要があります。

Shapesの描画は、JPanelのGraphicsオブジェクトを各Shapeに渡し、それを使用して描画を行う場合でした。

于 2011-08-30T14:58:29.490 に答える
1

最も簡単な方法は、イベントをキャッチして電話することだと思いますparent.processEvent()。したがって、コンポーネントはイベントを親に伝播するため、イベントに対して透過的です。

于 2011-08-30T13:32:37.710 に答える
0

contains私はこの種の質問に苦労していて、メソッドのオーバーライドがまさにあなたが望むことをすることに気付くまで、両親とガラス板ですべてのものを試しました。親が発砲すると、ある種のgetcomponent「ライン」がそれに応答するからです。「いいえ、それは私ではありません。私はそこにいません!」ループは他のコンポーネントをチェックします。また、ドラッグ可能なオブジェクトに複雑な深さを設定する必要がある場合は、JLayeredPaneの子孫を使用できます。

于 2013-04-12T11:12:03.527 に答える