Проблема с JTextPane с фоновым изображением и прямоугольником обрезки

У меня проблема с Swing, причину которой я просто не нахожу. У меня есть JTextPane, который был расширен для отображения фонового изображения. Это может быть растровое изображение (отображаемое через стандартные API-интерфейсы Java) или векторное изображение SVG (отображаемое через SVG Salamander).

Поскольку я хочу, чтобы на текстовой панели была область вверху, используемая в качестве поля, на котором не будет отображаться текст, я делаю следующее: я переопределяю paintComponent(), рисую фоновое изображение, затем вызываю super.paintComponent(), чтобы текст и т. д. будут показаны, и, наконец, я снова рисую часть фонового изображения, но с прямоугольником обрезки, чтобы покрыть только текст, который находится в области верхнего поля.

Это работает отлично, за исключением небольшого сбоя, с которым я боролся в течение нескольких дней: с растровым изображением, если я выбираю текст на текстовой панели, текст удаляется, а не выделяется. То есть, когда я выбираю текст, фоновое изображение отображается поверх тех частей, которые я выбираю. Я не понимаю, почему это может быть, так как первый вызов, который рисует изображение, вызывается перед super.paintComponent(), второй вызов имеет прямоугольник обрезки, поэтому он закрашивает только поле, и все работает нормально, если я не т сделать выбор. Некоторые дополнительные подсказки:

  • Я знаю, что это связано со вторым вызовом, так как, если я прокомментирую его, у меня не будет этой проблемы (хотя тогда у меня нет запаса).
  • Любопытно, что этого не происходит, когда фон представляет собой векторное изображение, только с растровым изображением.

Вот код моего метода paintComponent():

public void paintComponent(Graphics g)
{
    Rectangle rect = null;
    if ( rasterBackgroundImage != null )
    {
        rect = getVisibleRect();
        g.drawImage(rasterBackgroundImage.getImage(),rect.x,rect.y,rect.width,rect.height,this);
    }
    if ( vectorBackgroundImage != null )
    {
        rect = getVisibleRect();
        vectorBackgroundImage.setPreferredSize(new Dimension(rect.width,rect.height));
        vectorBackgroundImage.setScaleToFit(true);
        vectorBackgroundImage.paintIcon(this, g, rect.x, rect.y);
    }

    super.paintComponent(g);

    //if we want a non-scrolling top margin
    if ( rasterBackgroundImage != null )
    {
        g.setClip(rect.x,rect.y,rect.width,getMargin().top);
        g.drawImage(rasterBackgroundImage.getImage(),rect.x,rect.y,rect.width,rect.height,this);
    }
    if ( vectorBackgroundImage != null )
    {
        g.setClip(rect.x,rect.y,rect.width,getMargin().top);
        vectorBackgroundImage.setPreferredSize(new Dimension(rect.width,rect.height));
        vectorBackgroundImage.paintIcon(this, g, rect.x, rect.y);
    }

}

Если кто-то хочет взглянуть на весь класс, он находится здесь: http://code.google.com/p/aetheria/source/browse/trunk/age/src/eu/irreality/age/swing/FancyJTextPane.java?r=301

Обратите внимание, что я не прошу исправления, так как кажется, что проблема во взаимодействии с другими классами. Вот почему я не предоставил SSCCE: я пытался создать его, но если я использую этот класс изолированно... он действительно РАБОТАЕТ. Мне не удалось воспроизвести проблему за пределами всей системы, и я понятия не имею, какое взаимодействие вызывает ее. Но я был бы очень признателен всем, кто даст подсказки, указывающие мне правильное направление - может быть, кто-то видел подобное раньше и мог бы понять, что может быть причиной...

Обновление: мне удалось обойти проблему, отказавшись от использования setClip(). Я нашел этот ответ, рекомендующий не использовать setClip() в paintComponent(): проблема обрезки качания Java

Вместо использования прямоугольника обрезки теперь я создаю часть изображения, содержащую верхнюю часть изображения, которую я хочу нарисовать на поле, и рисую ее напрямую, не вызывая setClip(). Это, вероятно, довольно неэффективно, так как я храню два изображения в памяти, когда одного должно быть достаточно, но, по крайней мере, это работает (tm). Если кому-то интересно увидеть этот хак, он здесь (код на данный момент немного грязный): http://code.google.com/p/aetheria/source/browse/trunk/age/src/eu/irreality/age/swing/FancyJTextPane.java?r=305

Тем не менее, если кто-нибудь сможет выяснить точную причину, по которой использование setClip() таким образом вызывает эти проблемы, или знает эффективный способ решить эту проблему, было бы интересно. Спасибо за ответы на все вопросы! :)


person Al-Khwarizmi    schedule 18.06.2011    source источник
comment
У меня есть ощущение, что эту проблему будет трудно решить, если ее нельзя изолировать или воспроизвести. Как насчет SCCE M (средней длины), который не требует векторных изображений?   -  person Hovercraft Full Of Eels    schedule 18.06.2011
comment
Я буду продолжать пытаться сделать один. Я пытался это сделать, но проблема в том, что это не показало сбой. Я понятия не имею, какая внешняя операция, которую я выполняю с текстовой панелью, может вызвать такое поведение, я буду продолжать искать...   -  person Al-Khwarizmi    schedule 18.06.2011
comment
@Algorithm: Пожалуйста, дайте нам знать, как идут дела. Вы можете разместить свой код там же, где и раньше, и предоставить ссылки. Если вы это сделаете, меньше шансов, что люди загрузят и запустят его, чем если бы вы могли опубликовать SSCCE, но я уверен, что некоторые это сделают, поскольку это кажется интригующей проблемой. Удача!   -  person Hovercraft Full Of Eels    schedule 18.06.2011
comment
Я подтвердил, что второй вызов рисует части изображения за пределами графического клипа, когда текст выделен. Например, если я делаю первый вызов, рисующий фон в цвете, а второй — черно-белую версию изображения, выделение текста делает эти части фона черно-белыми.   -  person Al-Khwarizmi    schedule 18.06.2011


Ответы (2)


зачем заморачиваться с рисованием изображения с помощью paintComponent(s), если существует JLabel и Как использовать значок, другая ценная информация описано в Выполнение пользовательского рисования и расширено в 2D-графика, множество примеров здесь и 2D-Graphics-GUI

person mKorbel    schedule 18.06.2011

В дополнение к полезным ссылкам @mKorbel, вот несколько идей:

person trashgod    schedule 18.06.2011
comment
Спасибо за ваш интересный проект; извините, если предложения элементарны. - person trashgod; 18.06.2011