Не могу понять, как работают границы региона - PullRequest
0 голосов
/ 04 апреля 2019

В настоящее время я пишу CAD-подобную программу для логических схем (это моя первая программа с интенсивной графикой).Когда я размещаю компонент на схеме, скажем, в виде логического элемента AND (который является классом Region в его корне), я хочу иметь возможность взаимодействовать с ним (выбрать его, изменить его свойства и т. Д.).Все идет нормально.Я могу нажать на нее, и все идет хорошо.Однако, если я щелкну за его пределами, событие щелчка мыши все равно покажет компонент в качестве его источника (!).

Копая немного дальше, я поместил некоторые следы в обработчик щелчка мыши и обнаружил, что getBoundsInLocal() и getBoundsInParent() возвращают границы, которые примерно на 50% больше, чем должны быть.getLayoutBounds(), getWidth() и getHeight() возвращают правильное значение.

Панель, на которой расположены компоненты, является простым Pane объектом, но она использует setScaleX() и setScaleY() реализовать возможности масштабирования.Я попытался отключить их, но безуспешно.

public abstract class SchematicComponent
        extends Region {
    private Shape graphicShape = null;

    public Shape getGraphicShape() {
        if( isShapeDirty() ) {
            if( graphicShape != null ) {
                getChildren().remove( graphicShape );
            }

            graphicShape = createShape();

            markShapeDirty( false );
            if( graphicShape != null ) {
                getChildren().add( graphicShape );
            }
        }

        return graphicShape;
    }

    abstract protected Shape createShape();
}

abstract public class CircuitComponent
        extends SchematicComponent {
}

abstract public class LogicGate
        extends CircuitComponent {

    @Override
    protected void layoutChildren() {
        super.layoutChildren();

        Pin outPin;
        final double inputLength = getInputPinsMaxLength();

        // Layout the component around its center.
        // NOTE: I did try to set the center offset to 0 with no luck.
        Point2D centerOffset = getCenterPointOffset().multiply( -1 );

        Shape gateShape = getGraphicShape();
        if( gateShape != null ) {
            gateShape.setLayoutX( centerOffset.getX() + inputLength );
            gateShape.setLayoutY( centerOffset.getY() );
        }

        /* Layout the output pins. */
        outPin = getOutputPin();
        if( outPin != null ) {
            outPin.layout();

            outPin.setLayoutX( centerOffset.getX() + getWidth() );
            outPin.setLayoutY( centerOffset.getY() + getHeight() / 2 );
        }

        /* Compute the first input pin location and the gap between each
           pins */
        double pinGap = 2;
        double y;
        if( getInputPins().size() == 2 ) {
            y = centerOffset.getY() + getHeight() / 2 - 2;
            pinGap = 4;
        }
        else {
            y = centerOffset.getY() + ( getHeight() / 2 ) - getInputPins().size() + 1;
        }

        /* Layout the input pins */
        for( Pin inPin : getInputPins() ) {
            inPin.layout();

            inPin.layoutXProperty().set( centerOffset.getX() );
            inPin.layoutYProperty().set( y );

            y += pinGap;
        }
    }

}

// The actual object placed on the schematic
public class AndGate
        extends LogicGate {

    @Override
    protected double computePrefWidth( double height ) {
        // NOTE: computeMin/MaxWidth methods call this one

        double width = getSymbolWidth() + getInputPinsMaxLength();
        double length = 0;

        width += length;

        if( getOutputPin().getLength() > 0 ) {
            width += getOutputPin().getLength();
        }

        return width; // Always 16
    }

    @Override
    protected double computePrefHeight( double width ) {
        // NOTE: computeMin/MaxHeight methods call this one
        return getSymbolHeight() + getExtraHeight();  // Always 10
    }

    @Override
    protected Shape createShape() {
        Path shape;
        final double extraHeight = getExtraHeight();
        final double inputLength = getInputPinsMaxLength();
        final double outputLength = getOutputPin().getLength();

        /* Width and Height of the symbol itself (i,e, excluding the
           input/output pins */
        final double width = getWidth() - inputLength - outputLength;
        final double height = getHeight() - extraHeight;

        /* Starting point */
        double startX = 0;
        double startY = extraHeight / 2;

        ArrayList<PathElement> elements = new ArrayList<>();
        elements.add( new MoveTo( startX, startY ) );
        elements.add( new HLineTo( startX + ( width / 2 ) ) );
        elements.add( new ArcTo( ( width / 2 ), // X radius
                                 height / 2, // Y radius
                                 180, // Angle 180°
                                 startX + ( width / 2 ), // X position
                                 startY + height, // Y position
                                 false, // large arc
                                 true ) ); // sweep
        elements.add( new HLineTo( startX ) );

        if( extraHeight > 0 ) {
            /* The height of the input pins is larger than the height of
               the shape so we need to add extra bar on top and bottom of 
               the shape.
             */
            elements.add( new MoveTo( startX, 0 ) );
            elements.add( new VLineTo( extraHeight + height ) );

        }
        else {
            elements.add( new VLineTo( startY ) );
        }

        shape = new Path( elements );
        shape.setStroke( getPenColor() );
        shape.setStrokeWidth( getPenSize() );
        shape.setStrokeLineJoin( StrokeLineJoin.ROUND );
        shape.setStrokeLineCap( StrokeLineCap.ROUND );
        shape.setFillRule( FillRule.NON_ZERO );
        shape.setFill( getFillColor() );

        return shape;
    }
} // End: LogiGate

// SchematicView is the ScrollPane container that handles the events
public class SchematicView
        extends ScrollPane {

    /* Mouse handler inner class */
    private class MouseEventHandler
            implements EventHandler<MouseEvent> {

    @Override
    public void handle( MouseEvent event ) {
        if( event.getEventType() == MouseEvent.MOUSE_CLICKED ) {
            processMouseClicked( event );
        }
        else { /* ... more stuff ... */ }
     }

    private void processMouseClicked( MouseEvent event ) {
        Object node = event.getSource();
        SchematicSheet sheet = getSheet();

        Bounds local = ( (Node) node ).getLayoutBounds();
        Bounds local1 = ( (Node) node ).getBoundsInLocal();
        Bounds parent = ( (Node) node ).getBoundsInParent();

        // At this point, here is what I get:
        // node.getHeight() = 10    -> Good
        // local.getHeight() = 10   -> Good
        // local1.getHeight() = 15.6499996...   -> Not expected!
        // parent.getHeight() = 15.6500015...   -> Not expected!

        /*... More stuff ... */
    }
}

Итак, на данный момент я пытаюсь понять, что происходит.Откуда эти getBoundsInXXX() значения?Они также не соответствуют значениям шкалы родителя.То же самое относится и к getWidth(): я получаю 24,825000 ... вместо 16.

Глядя на это, я понимаю, почему нажатие за пределы компонента работает так, как будто я щелкнул по нему.Его границы примерно на 50% больше, чем должно быть.

Я гуглил эту чертову штуку и искал какой-то документ почти 2 дня, и я все еще сбит с толку.Я думаю, я понимаю, что getBoundsInXXX() методы делают свои собственные вычисления, но может ли это быть слишком много?Я так не думаю.Я думаю, что это что-то внутри createShape() метода, но я просто не могу понять, что это такое.

Кто-нибудь знает, что происходит?

Большое спасибо заВаша помощь.

PS: Это мой первый пост здесь, так что, надеюсь, я все сделал правильно;)

1 Ответ

0 голосов
/ 24 апреля 2019

Я думаю, что наконец-то нашел проблему:)

По сути, пользовательская форма Pin была нарисована в отрицательной части оси X (неправильные вычисления, мой плохой!).Мое лучшее предположение заключается в том, что Java как-то замечает, что я нарисовал за пределами стандартных границ, а затем добавил дополнительное пространство, используемое для границ, следовательно, добавив 50% к ширине, что соответствует длине Pin.Рисование в положительной области, похоже, решило проблему.

Я не на 100% уверен, что это правильный ответ, но он имеет смысл, и теперь он работает, как и ожидалось.

...