Используя JTextPane, потребляемые события мыши по-прежнему распространяются на обновления каретки/обновления выбора.

Кажется, у меня проблема с JTextPane. Я расширил JTextPane для рендеринга плавающего изображения, потому что функциональность значка JTextPane не соответствует моей цели. Я хочу, чтобы пользователь мог щелкнуть изображение и выполнить определенные события. Однако, когда я нажимаю на изображение, даже когда я использую evt.consume(), курсор и выделение обновляются в JTextPane. Я хотел бы, чтобы клики и события мыши в целом, которые взаимодействуют с изображением, вообще не влияли на положение каретки или выбор. Соответствующий код:

public class JTextPaneImg extends JTextPane {

    public JTextPaneImg(){
        super();
        addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                formMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                formMouseReleased(evt);
            }
        });
    }

    private void formMousePressed(java.awt.event.MouseEvent evt) {                                  
        if (imgBound.contains(evt.getPoint())) {
             evt.consume();
             //Do some stuff in here to interact with the image
             // but the event still undesirably interacts with selection/caret
        }
    }   


    private void formMouseReleased(java.awt.event.MouseEvent evt) {                                  
        if (imgBound.contains(evt.getPoint())) {
             evt.consume();
             //Do some stuff in here to interact with the image
             // but the event still undesirably interacts with selection/caret
        }
    }   
}

Я даже вызвал getMouseListeners и проверил, что мой собственный прослушиватель мыши является последним в массиве, я читал, что прослушиватели вызываются от самого высокого к самому низкому индексу, что означает, что если мой прослушиватель вызывает потребление, он должен быть последним, чтобы воздействовать на событие. Почему мое событие щелчка мыши все еще обновляет каретку? Это проблема с внешним видом?


person Monolithguy    schedule 09.11.2010    source источник
comment
Я думаю, что, возможно, нашел подсказку: курсор для JTextPane по умолчанию является BasicCaret из BasicTextUI, который по сути является точной копией DefaultCaret. Метод обновления DefaultCaret выглядит следующим образом: protected void moveCaret (MouseEvent e) { Point pt = new Point (e.getX(), e.getY()); Position.Bias[]biasRet = new Position.Bias[1]; int pos = component.getUI().viewToModel(component, pt,biaRet); if(biasRet[0] == null)biasRet[0] = Position.Bias.Forward; if (pos ›= 0) { moveDot(pos,biasRet[0]); } } обратите внимание на отсутствие if(!e.isConsumed)   -  person Monolithguy    schedule 09.11.2010


Ответы (2)


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

Этот порядок не гарантируется. Гарантируется только то, что все слушатели будут уведомлены. Я считаю, что каждый слушатель должен проверить, используется ли событие. По крайней мере, это мое понимание

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

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

Или, может быть, ваше изображение должно быть нарисовано в окне просмотра, а не в текстовой панели.

person camickr    schedule 09.11.2010
comment
Хотя мой ответ выше создал желаемое поведение, ясно, что вы лучше знакомы с передовыми методами, чем я, говоря, что изображение должно быть нарисовано в окне просмотра, а не в текстовой панели. Я также изучу это решение. - person Monolithguy; 09.11.2010

Решено созданием собственного каретки. Проблема заключалась в том, что реализация DefaultCaret НЕ проверяет e.isConsumed на события мыши, поэтому вы должны переопределить и добавить проверку isconsumed. Моя текстовая панель теперь ведет себя так, как предполагалось, когда у меня есть следующий код в конструкторе:

    this.setCaret(new DefaultCaret() {

        @Override
        protected void positionCaret(MouseEvent e) {
            if (!e.isConsumed()) super.positionCaret(e);
        }

        @Override
        protected void moveCaret(MouseEvent e) {
            if (!e.isConsumed()) super.moveCaret(e);
        }
    });

Это моя вина, что я не до конца понял роль Каре в событийной модели. Но, если вы спросите меня, это несколько глупо. Из документации, которую я прочитал, соглашение состоит в том, чтобы все слушатели действовали ощутимо только в том случае, если !e.isConsumed().

person Monolithguy    schedule 09.11.2010