Как создать щелчок через компоненты в Java Swing? - PullRequest
4 голосов
/ 30 августа 2011

Я создал пользовательский компонент, который показывает только строку. Линия рисуется от верхнего левого угла до нижнего правого угла как Line2D в методе рисования. Фон прозрачный. Я расширил JComponent. Эти линейные компоненты перетаскиваются и меняют свой цвет линии, когда указатель мыши расположен макс. 15 пикселей от нарисованной линии. Но если у меня есть несколько этих компонентов, добавленных в другой пользовательский компонент, который расширяет JPanel, они иногда перекрываются. Я хочу реализовать, что если указатель мыши находится на расстоянии более 15 пикселей от линии, события мыши должны проходить через компонент. Как позволить этому провалиться - моя проблема. Это вообще возможно?

Заранее спасибо!

Ответы [ 5 ]

3 голосов
/ 30 августа 2011

Я хочу реализовать это, если указатель мыши больше 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);
         }
    }
}
2 голосов
/ 30 августа 2011

Для моего последнего года обучения в университете я выполнил программу для доски, и у меня возникла та же проблема. Для каждой фигуры, которую пользователь рисовал на доске, я создал JComponent, что было хорошо, когда они рисовали прямоугольники, но сложнее с инструментом линии свободной формы.

В конце концов, я исправил все это, покончив с JComponents. У меня был JPanel, который содержал Vector (я думаю) пользовательских объектов Shape. Каждый объект имел свои координаты и толщину линий и тому подобное. Когда пользователь нажимал на доску, слушатель мыши на JPanel запускал и проходил через каждый Shape, вызывая метод содержимого (int x, int y) для каждого (x и y - координаты события). Поскольку фигуры были добавлены в вектор по мере их отрисовки, я знал, что последним, вернувшим значение true, была самая верхняя фигура.

Это то, что я использовал для метода прямой линии. Математика может быть немного ненадежной, но это сработало для меня.

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 - это, да, конец строки. Возвращается значение true, если щелчок находится в пределах lineThickness / 2 от центра линии, в противном случае необходимо щелкнуть вправо вдоль самой середины линии.

Рисование фигур - это случай передачи объекта Graphics в JPanel каждому Shape и выполнения рисования с этим.

2 голосов
/ 30 августа 2011

Прошло много времени с тех пор, как я коснулся Swing, но я думаю, что вам нужно обработать события мыши в родительском компоненте, а затем перебрать дочерние компоненты со строками и определить, какой из них должен обрабатывать событие (ну логика принятия решения все еще должна оставаться в компоненте строки, но родительский объект будет явно вызывать эту логику до тех пор, пока один из компонентов не примет событие).

1 голос
/ 30 августа 2011

Я считаю, что самый простой способ - поймать событие и позвонить parent.processEvent().Таким образом, ваш компонент будет прозрачным для событий, потому что он будет передавать их родителю.

0 голосов
/ 12 апреля 2013

Я боролся с такого рода вопросами и пробовал все с родителями и стеклом, пока не понял, что переопределение метода contains делает то, что вы хотите.Потому что когда родитель запускает какой-то getcomponent, ваша «Линия» ответит ему: «Нет, это не я, меня там нет!»и цикл проверит другие компоненты.Также, когда вам нужно установить сложную глубину для вашего перетаскиваемого объекта, вы можете использовать потомок JLayeredPane.

...