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

发布于 2024-07-30 19:51:23 字数 5561 浏览 7 评论 0原文

我最近购买了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);
    }
}

I recently purchased the book Filthy Rich Clients and i found it really useful and fun. Building on one example from the book i tried implementing a custom ScrollPane that displays a "shadow" on the bottom of its view over the component to be displayed. I ended up with the code below. It works but not perfectly. Specifically when i scroll the pane by dragging the scroll bar everything works ok and the painting is really smooth. But when i scroll with the mouse scroll the shadow flickers and i have no idea why. Can anyone help me?

EDIT: Same thing happens for any component in the scroll pane. Edited the code to display two frames to see the problem.

EDIT 2 : I have isolated the issue to the way the scroll pane handles the mouse wheel event. When scrolling the scroll pane copies the contents of the view port slightly up or down depending on the orientation of the scroll and then draws the region that comes into view. My code makes the whole component "dirty" but that is after the component has shifted the contents. So momentarily you see the "shadow" gradient out of place until a repaint is issued. Any ideas on how to disable this functionality?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雨巷深深 2024-08-06 19:51:23

您是否尝试过在 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,因此也许可以尝试其他选项之一。

Have you tried calling setWheelScrollingEnabled(false) on the ScrollPane object?

From the javadoc:

Enables/disables scrolling in
response to movement of the mouse
wheel. Wheel scrolling is enabled by
default.

Update following the comment by Savvas below.

Perhaps the "setScrollMode(int)" method on the viewport can help you. This method will determine how swing scrolls the viewport.

You can get the viewport directly from the ScrollPane with the getViewPort() method.
You have the following options:

BLIT_SCROLL_MODE
BACKINGSTORE_SCROLL_MODE
SIMPLE_SCROLL_MODE

According to the javadoc BLIT_SCROLL_MODE will use Graphics.copyArea so perhaps try one of the others.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文