如何在Java中创建大型自定义光标?

弗兰克:

我正在为屡获殊荣的密码保护系统开发Java Swing应用程序,并且我需要一个大型自定义光标[80 x 80],您可能会问为什么这么大,有一个在线Web演示您可以查看以了解为什么需要很大:http : //gatecybertech.net

上面的链接在登录页面上使用了那个大光标。当然,您需要先创建测试密码,然后才能尝试登录过程。

但是无论如何,在我的Swing应用程序中,对于最大可能的自定义光标,我达到了32 x 32的限制,我的代码如下所示:

Image cursorImage = toolkit.getImage("Cursor_Crosshair.PNG");
Tabular_Panel.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(cursorImage,new Point(0,0),"custom cursor"));

Cursor_Crosshair.PNG的图像大小为:80 x 80

但是屏幕上显示的是它的缩小版本:32 x 32

所以我的问题是:如何绕过客户光标图像的大小限制,并使光标显示为80 x 80的大小?

我知道操作系统可能是限制的原因,有没有办法克服它?

Radiodef:

这是我对玻璃窗格绘画方法的看法。设置它的行为就像设置自定义光标一样。当显示自定义光标时,默认的“箭头”光标被隐藏,而当组件设置了其他光标(例如文本框)时,自定义光标被隐藏。

不幸的是,它最终似乎需要大量的Swing黑魔法,所以我不太喜欢它,但它确实可以正常工作。我之前已经做过这样的游标,但这是为了更简单一些,所以我没有遇到这些问题。

我遇到的一些问题是:

  • 玻璃窗格拦截光标更改(例如,在此处对此进行了描述)。我已经能够找到的唯一解决办法是重写Component.contains(int,int)返回false(形容这里,显示这里),但为什么作品似乎并没有打破任何东西是神秘的。

  • 鼠标退出事件有时会在组件范围内返回一个位置,因此我认为除了使用计时器之外,没有一种可靠的方法来知道鼠标何时离开窗口。

package mcve;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.net.*;
import java.io.*;

public class LargeCursor {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame();

            JPanel glass = new CustomGlassPane();
            glass.add(new CursorPanel(), BorderLayout.CENTER);
            frame.setGlassPane(glass);
            // This next call is necessary because JFrame.setGlassPane delegates to the root pane:
            // - https://docs.oracle.com/javase/9/docs/api/javax/swing/RootPaneContainer.html#setGlassPane-java.awt.Component-
            // - http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/javax/swing/JFrame.java#l738
            // And JRootPane.setGlassPane may call setVisible(false):
            // - https://docs.oracle.com/javase/9/docs/api/javax/swing/JRootPane.html#setGlassPane-java.awt.Component-
            // - http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/javax/swing/JRootPane.java#l663
            glass.setVisible(true);

            JPanel content = createTestPanel();
            content.setCursor(BlankCursor.INSTANCE);

            frame.setContentPane(content);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }

    static class CustomGlassPane extends JPanel {
        CustomGlassPane() {
            super(new BorderLayout());
            super.setOpaque(false);
        }
        @Override
        public boolean contains(int x, int y) {
            return false;
        }
    }

    static class CursorPanel extends JPanel {
        final BufferedImage cursorImage;
        Point mouseLocation;

        CursorPanel() {
            try {
                cursorImage = createTransparentImage(
                    ImageIO.read(new URL("https://i.stack.imgur.com/9h2oI.png")));
            } catch (IOException x) {
                throw new UncheckedIOException(x);
            }

            setOpaque(false);

            long mask = AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK;

            Toolkit.getDefaultToolkit().addAWTEventListener((AWTEvent e) -> {
                switch (e.getID()) {
                    case MouseEvent.MOUSE_ENTERED:
                    case MouseEvent.MOUSE_EXITED:
                    case MouseEvent.MOUSE_MOVED:
                    case MouseEvent.MOUSE_DRAGGED:
                        capturePoint((MouseEvent) e);
                        break;
                }
            }, mask);

            // This turned out to be necessary, because
            // the 'mouse exit' events don't always have
            // a Point location which is outside the pane.
            Timer timer = new Timer(100, (ActionEvent e) -> {
                if (mouseLocation != null) {
                    Point p = MouseInfo.getPointerInfo().getLocation();
                    SwingUtilities.convertPointFromScreen(p, this);
                    if (!contains(p)) {
                        setMouseLocation(null);
                    }
                }
            });
            timer.setRepeats(true);
            timer.start();
        }

        void capturePoint(MouseEvent e) {
            Component comp = e.getComponent();
            Point onThis = SwingUtilities.convertPoint(comp, e.getPoint(), this);
            boolean drawCursor = contains(onThis);

            if (drawCursor) {
                Window window = SwingUtilities.windowForComponent(this);
                if (window instanceof JFrame) {
                    Container content = ((JFrame) window).getContentPane();
                    Point onContent = SwingUtilities.convertPoint(comp, e.getPoint(), content);
                    Component deepest = SwingUtilities.getDeepestComponentAt(content, onContent.x, onContent.y);
                    if (deepest != null) {
                        if (deepest.getCursor() != BlankCursor.INSTANCE) {
                            drawCursor = false;
                        }
                    }
                }
            }

            setMouseLocation(drawCursor ? onThis : null);
        }

        void setMouseLocation(Point mouseLocation) {
            this.mouseLocation = mouseLocation;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            if (mouseLocation != null) {
                int x = mouseLocation.x - (cursorImage.getWidth() / 2);
                int y = mouseLocation.y - (cursorImage.getHeight() / 2);

                g.drawImage(cursorImage, x, y, this);
            }
        }
    }

    static final class BlankCursor {
        static final Cursor INSTANCE =
            Toolkit.getDefaultToolkit().createCustomCursor(
                new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
                new Point(),
                "BLANK");
    }

    static JPanel createTestPanel() {
        JPanel panel = new JPanel(new GridLayout(3, 3));
        panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));

        for (int i = 0; i < 9; ++i) {
            if ((i % 2) == 0) {
                JTextField field = new JTextField("Text Field");
                field.setHorizontalAlignment(JTextField.CENTER);
                panel.add(field);
            } else {
                panel.add(new JButton("Button"));
            }
        }

        return panel;
    }

    static BufferedImage createTransparentImage(BufferedImage img) {
        BufferedImage copy =
            GraphicsEnvironment.getLocalGraphicsEnvironment()
                               .getDefaultScreenDevice()
                               .getDefaultConfiguration()
                               .createCompatibleImage(img.getWidth(),
                                                      img.getHeight(),
                                                      Transparency.TRANSLUCENT);
        for (int x = 0; x < img.getWidth(); ++x) {
            for (int y = 0; y < img.getHeight(); ++y) {
                int rgb = img.getRGB(x, y) & 0x00FFFFFF;
                int bright = (((rgb >> 16) & 0xFF) + ((rgb >> 8) & 0xFF) + (rgb & 0xFF)) / 3;
                int alpha = 255 - bright;
                copy.setRGB(x, y, (alpha << 24) | rgb);
            }
        }

        return copy;
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章