在Java Swing窗口中更新自定义光标

2ekbmq32  于 2023-01-24  发布在  Java
关注(0)|答案(2)|浏览(162)

我想在我的java swing应用程序中设置自定义光标,然后编辑它。
我在显示窗口后设置了一个自定义光标(在“Window”类中)。稍后在代码中(在另一个类中),我想再次链接它,所以我调用了这个updateCursor()函数(再次在“Window”类中),它和它不会工作。没有错误或警告,但光标没有改变-只是保持不变。我尝试了,我在任何地方都找不到答案。我感谢任何帮助。
这是完整的代码-Window.java

import MainMenu;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;

public class Window {
    public static final int WIDTH = 817, HEIGHT = 640;

    JFrame frame = new JFrame("");

    public void open() {
        frame.pack();
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setSize(WIDTH - 33, HEIGHT - 25);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setFocusable(true);
        frame.requestFocus();
        frame.setFocusTraversalKeysEnabled(true);

        frame.addKeyListener(new InputManager());
        frame.addMouseListener(new InputManager());
        frame.add(new MainMenu());
        frame.add(new Game());

        loadCursors();

        updateCursor(0);
    }

    public static final int NORMAL = 0, ACTIVE = 1, INACTIVE = 2;

    Cursor cursor_normal, cursor_active, cursor_inactive;

    public void loadCursors() {
        try {
            cursor_normal = Toolkit.getDefaultToolkit().createCustomCursor(ImageIO.read(new File(new SpritesManager().cursor_normal)), new Point(0, 0), "custom cursor (normal)");
            cursor_active = Toolkit.getDefaultToolkit().createCustomCursor(ImageIO.read(new File(new SpritesManager().cursor_active)), new Point(0, 0), "custom cursor (active)");
            cursor_inactive = Toolkit.getDefaultToolkit().createCustomCursor(ImageIO.read(new File(new SpritesManager().cursor_inactive)), new Point(0, 0), "custom cursor (inactive)");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void updateCursor(int cursorType) {
        switch (cursorType) {
            case NORMAL -> frame.setCursor(cursor_normal);
            case ACTIVE -> frame.setCursor(cursor_active);
            case INACTIVE -> frame.setCursor(cursor_inactive);
        }
    }
}

主菜单.java

import Window;

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class MainMenu extends JPanel implements KeyListener {

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        // testing
        new Window().updateCursor(Window.ACTIVE);
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}
e5nszbig

e5nszbig1#

你不能...

new Window().updateCursor(Window.ACTIVE);

并且神奇地期望Window的另一个示例被更新,实际上,您根本不需要这样做。
这将创建Window的另一个示例/副本,该示例/副本未显示在屏幕上,并且不会对显示的示例产生影响。
您可以直接在示例MainMenu上调用setCursor
现在,如果您想"集中"功能,我将从创建一个"manager"类开始,例如...

public class CursorManager {

    public enum CusorType {
        NORMAL, ACTIVE, INACTIVE;
    }

    private Cursor cursorNormal, cursorActive, cursorInactive;

    public CursorManager() throws IOException {
        cursorNormal = Toolkit.getDefaultToolkit().createCustomCursor(ImageIO.read(new File(new SpritesManager().cursor_normal)), new Point(0, 0), "custom cursor (normal)");
        cursorActive = Toolkit.getDefaultToolkit().createCustomCursor(ImageIO.read(new File(new SpritesManager().cursor_active)), new Point(0, 0), "custom cursor (active)");
        cursorInactive = Toolkit.getDefaultToolkit().createCustomCursor(ImageIO.read(new File(new SpritesManager().cursor_inactive)), new Point(0, 0), "custom cursor (inactive)");
    }

    public void setCursor(CusorType cursorType, Component comp) {
        switch (cursorType) {
            case NORMAL ->
                comp.setCursor(cursorNormal);
            case ACTIVE ->
                comp.setCursor(cursorActive);
            case INACTIVE ->
                comp.setCursor(cursorInactive);
        }
    }
}

然后,我将在代码的初始化阶段创建管理器的此示例

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                CursorManager cursorManager = new CursorManager();
                //.. Every thing else...
            } catch (IOException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });
}

然后将此示例传递给每个可能需要它的类...

// You'll need to update Window to accept this parameter
new Window(cursorManager).open();

还有...

public class MainMenu extends JPanel implements KeyListener {

    private CursorManager cursorManager;
    
    private MainMenu(CursorManager cursorManager) {
        this.cursorManager = cursorManager;
    }

    @Override
    public void keyPressed(KeyEvent e) {
        // testing
        cursorManager.setCursor(CursorManager.CusorType.ACTIVE, this);
    }

    //...
}

这通常称为"依赖注入",功能非常强大

反馈

顺便说一句,如果我在做这样的事情,情况会有很大的不同,但我尽量保持简单。

  • 我们通常不鼓励从JFrame这样的顶级容器进行扩展,正如前面所述,JFrame不是一个简单的组件,您实际上并没有向类添加任何新功能,在此过程中,您将自己锁定为单一用途,最好从JPanel作为基本组件开始,然后简单地创建JFrame的示例或"JDialog或您想要使用的任何顶级容器(当您需要它时
  • KeyListener是监视键盘输入的一个糟糕的选择(说真的,只要搜索"我的键监听器不工作"就行了,相反,看看How to Use Key Bindings
bnlyeluc

bnlyeluc2#

您正在keyPressed(..)方法中创建Window类的新示例,因此光标更新不起作用:
新建窗口().更新光标(窗口.活动);
您需要将现有的Window示例传递给MainMenu类并调用此示例。
下面是一个工作示例:

    • 主应用程序**:
public class MyApp extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MyApp app = new MyApp();
                app.setVisible(true);
            }
        });
    }

    private MyApp() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 600);

        // Create cursors
        Cursor c1 = Util.getCursor("c1.png");
        Cursor c2 = Util.getCursor("c2.png");

        setCursor(c1);

        JButton button1 = new JButton("Change to Cursor1");
        button1.setActionCommand("c1");
        button1.addActionListener(new MyActionListener(this));

        JButton button2 = new JButton("Change to Cursor2");
        button2.setActionCommand("c2");
        button2.addActionListener(new MyActionListener(this));

        add(button1, BorderLayout.NORTH);
        add(button2, BorderLayout.SOUTH);
    }

}
    • ActionListener**(处理按钮点击):
public class MyActionListener implements ActionListener {

    private JFrame jFrame;

    public MyActionListener(JFrame jFrame) {
        this.jFrame = jFrame;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        switch (e.getActionCommand()){
            case "c1":
                jFrame.setCursor(Util.getCursor("c1.png"));
                System.out.println("switch to c1");
                break;
            case "c2":
                jFrame.setCursor(Util.getCursor("c2.png"));
                System.out.println("switch to c2");
                break;
        }
    }

}
    • 实用程序**(读取光标图像):
public class Util {
    public static Cursor getCursor(String fileName) {
        BufferedImage img = null;
        try {
            img = ImageIO.read(Util.class.getResourceAsStream(fileName));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Toolkit.getDefaultToolkit().createCustomCursor(img, new Point(0, 0), fileName);
    }

}

相关问题