Как отключить поведение рисования по умолчанию для события прокрутки колеса на JScrollPane

Недавно я купил книгу Filthy Rich Clients и нашел ее действительно полезной и интересной. Основываясь на одном примере из книги, я попытался реализовать пользовательскую панель прокрутки, которая отображает «тень» в нижней части своего представления над отображаемым компонентом. Я закончил с кодом ниже. Он работает, но не идеально. В частности, когда я прокручиваю панель, перетаскивая полосу прокрутки, все работает нормально, и рисование действительно гладкое. Но когда я прокручиваю мышью, тень мерцает, и я понятия не имею, почему. Может кто-нибудь помочь мне?

EDIT: то же самое происходит с любым компонентом в области прокрутки. Отредактировал код для отображения двух кадров, чтобы увидеть проблему.

РЕДАКТИРОВАТЬ 2. Я выделил проблему, связанную с тем, как панель прокрутки обрабатывает событие колесика мыши. При прокрутке панель прокрутки копирует содержимое окна просмотра немного вверх или вниз в зависимости от ориентации прокрутки, а затем рисует область, которая попадает в поле зрения. Мой код делает весь компонент «грязным», но это происходит после того, как компонент сместил содержимое. Таким образом, на мгновение вы видите градиент «тени» не на своем месте, пока не будет выполнено перерисовывание. Есть идеи, как отключить эту функцию?

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.RepaintManager;

public class Test {

    public static void main(String[] args) {
        JFrame f = new JFrame("Table");
        JFrame f1 = new JFrame("Text Area");
        Object[] names = new Object[] { "Title", "Artist", "Album" };
        String[][] data = new String[][] {
                { "Los Angeles", "Sugarcult", "Lights Out" },
                { "Do It Alone", "Sugarcult", "Lights Out" },
                { "Made a Mistake", "Sugarcult", "Lights Out" },
                { "Kiss You Better", "Maximo Park", "A Certain Trigger" },
                { "All Over the Shop", "Maximo Park", "A Certain Trigger" },
                { "Los Angeles", "Sugarcult", "Lights Out" },
                { "Do It Alone", "Sugarcult", "Lights Out" },
                { "Made a Mistake", "Sugarcult", "Lights Out" },
                { "Kiss You Better", "Maximo Park", "A Certain Trigger" },
                { "All Over the Shop", "Maximo Park", "A Certain Trigger" },
                { "Los Angeles", "Sugarcult", "Lights Out" },
                { "Do It Alone", "Sugarcult", "Lights Out" },
                { "Made a Mistake", "Sugarcult", "Lights Out" },
                { "Kiss You Better", "Maximo Park", "A Certain Trigger" },
                { "All Over the Shop", "Maximo Park", "A Certain Trigger" },
                { "Los Angeles", "Sugarcult", "Lights Out" },
                { "Do It Alone", "Sugarcult", "Lights Out" },
                { "Made a Mistake", "Sugarcult", "Lights Out" },
                { "Kiss You Better", "Maximo Park", "A Certain Trigger" },
                { "All Over the Shop", "Maximo Park", "A Certain Trigger" },
                { "Los Angeles", "Sugarcult", "Lights Out" },
                { "Do It Alone", "Sugarcult", "Lights Out" },
                { "Made a Mistake", "Sugarcult", "Lights Out" },
                { "Kiss You Better", "Maximo Park", "A Certain Trigger" },
                { "All Over the Shop", "Maximo Park", "A Certain Trigger" },
                { "Going Missing", "Maximo Park", "A Certain Trigger" } };
        JTable table = new JTable(data, names);
        f.getContentPane().add(new ShadowScrollPane(table));
        f1.getContentPane().add(new ShadowScrollPane(new JTextArea(20, 50)));
        RepaintManager.setCurrentManager(new RepaintManager(){
            @Override
            public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
                Container con = c.getParent();
                while (con instanceof JComponent) {
                    if (!con.isVisible()) {
                        return;
                    }
                    if (con instanceof ShadowScrollPane ) {
                        c = (JComponent)con;
                        x = 0;
                        y = 0;
                        w = con.getWidth();
                        h = con.getHeight();
                    }
                    con = con.getParent();
                }
                super.addDirtyRegion(c, x, y, w, h);
            }
        });
        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        f1.pack();
        f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f1.setVisible(true);
    }

}

@SuppressWarnings("serial")
class ShadowScrollPane extends JScrollPane {

    private final int h = 50;
    private BufferedImage img = null;
    private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);

    public ShadowScrollPane(JComponent com) {
        super(com);
        Graphics2D g2 = shadow.createGraphics();
        g2.setPaint(new Color(50, 50, 50));
        g2.fillRect(0, 0, 1, h);
        g2.setComposite(AlphaComposite.DstIn);
        g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h, new Color(1, 1, 1, 0.6f)));
        g2.fillRect(0, 0, 1, h);
        g2.dispose();
    }

    @Override
    public void paint(Graphics g) {
        if (img == null || img.getWidth()!=getWidth() || img.getHeight() != getHeight()) {
            img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        }
        Graphics2D g2 = img.createGraphics();
        super.paint(g2);
        Rectangle bounds = getViewport().getVisibleRect();
        g2.scale(bounds.getWidth(), -1);
        int y = (getColumnHeader()==null)?0:getColumnHeader().getHeight();
        g2.drawImage(shadow, bounds.x, -bounds.y - y-h, null);
        g2.scale(1,-1);
        g2.drawImage(shadow, bounds.x, bounds.y + bounds.height-h+y, null);
        g2.dispose();
        g.drawImage(img, 0, 0, null);
    }
}

person Savvas Dalkitsis    schedule 08.08.2009    source источник
comment
см. мой пост stackoverflow.com/questions/ 8197261/, спасибо за отличный вопрос +1   -  person mKorbel    schedule 20.11.2011


Ответы (1)


Вы пытались вызвать setWheelScrollingEnabled(false) для объекта ScrollPane?

Из javadoc:

Включает/отключает прокрутку в ответ на движение колесика мыши. Прокрутка колеса включена по умолчанию.

Обновление после комментария Савваса ниже.

Возможно, вам поможет метод setScrollMode(int) в окне просмотра. Этот метод будет определять, как свинг прокручивает окно просмотра.

Вы можете получить область просмотра непосредственно из ScrollPane с помощью метода getViewPort(). У вас есть следующие варианты:

BLIT_SCROLL_MODE
BACKINGSTORE_SCROLL_MODE
SIMPLE_SCROLL_MODE

Согласно javadoc BLIT_SCROLL_MODE будет использовать Graphics.copyArea, поэтому, возможно, попробуйте один из других.

person Aaron    schedule 08.08.2009
comment
я хочу сохранить поведение прокрутки. Чего я не хочу, так это сохранять то, как панель прокрутки рисует себя при прокрутке. По-видимому, он не использует метод перерисовки, но использует метод Graphics.copyArea(x, y, width, height, dx, dy). После этого вызывается перерисовка, чтобы закрасить недавно введенную область, и поскольку я пометил весь компонент как грязный, мой метод рисования срабатывает. Но после copyArea появляется мигание. - person Savvas Dalkitsis; 09.08.2009
comment
Спасибо. Это сработало как шарм. И JViewport.BACKINGSTORE_SCROLL_MODE, и JViewport.SIMPLE_SCROLL_MODE работают так, как я хочу. - person Savvas Dalkitsis; 09.08.2009