如何在JScrollPane上禁用轮滚动事件的默认绘制行为

时间:2009-08-08 16:33:47

标签: java swing java-2d repaint

我最近购买了这本书Filthy Rich Clients,我发现它非常实用且有趣。在本书的一个例子的基础上,我尝试实现一个自定义ScrollPane,它在要显示的组件的视图底部显示一个“阴影”。我最终得到了下面的代码。它工作但不完美。特别是当我通过拖动滚动条滚动窗格时,一切正常,绘画非常流畅。但是当我用鼠标滚动滚动时,阴影闪烁,我不明白为什么。任何人都可以帮助我吗?

编辑:滚动窗格中的任何组件都会发生同样的事情。编辑代码以显示两个帧以查看问题。

编辑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);
    }
}

1 个答案:

答案 0 :(得分:3)

您是否尝试在ScrollPane对象上调用setWheelScrollingEnabled(false)?

来自javadoc:

  

启用/禁用滚动   对鼠标移动的反应   轮。滚轮滚动已启用   默认值。

按照以下Savvas的评论更新。

也许视口上的“setScrollMode(int)”方法可以帮到你。此方法将确定swing如何滚动视口。

您可以使用getViewPort()方法直接从ScrollPane获取视口。 您有以下选择:

BLIT_SCROLL_MODE
BACKINGSTORE_SCROLL_MODE
SIMPLE_SCROLL_MODE

根据javadoc BLIT_SCROLL_MODE将使用Graphics.copyArea,所以也许尝试其中一个。