不能将.addKeyListener(this)用于静态JPanel,但需要JPanel保持静态 - Java

use*_*991 1 java swing static keylistener jpanel

我正在尝试制作一个简单的程序,其中椭圆跟随鼠标光标,如果在键盘上输入"r","g"或"b",椭圆会相应地改变颜色.

但是,我无法使我的KeyListener工作.这是我的问题.我有一个静态JPanel,因为我需要它可以在所有函数和方法中访问.但是,Java不允许您使用静态JPanel执行此操作.我需要JPanel是静态的,所以我可以在keyPressed(KeyEvent e)函数中设置颜色.

我非常了解Java的基础知识,并且正在掌握一些更复杂的概念.请尝试解释是否有任何复杂的代码.谢谢!

这是主要类Drivers.java中的代码.

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

public class Drivers implements KeyListener 
{

    // panel.red = panel.red - 3;
    // panel.green = panel.green - 3;
    // panel.blue = panel.blue - 3;

    public static JFrame frame = new JFrame();
    public static ShapesPanel panel = new ShapesPanel().addKeyListener(this);
    // Notice the error we get with the addKeyListener(this);

    public static void main(String[] args)
    {
        // Creates new pointer info
        PointerInfo info;
        // Creates a point (for mouse tracking)
        Point point;
        JLabel label = new JLabel();
        panel.add(label);
        // Set window size
        panel.setPreferredSize(new Dimension(300, 350));
        // Set panel inside frame
        frame.setContentPane(panel);
        // Transparent 16 x 16 pixel cursor image.
        BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
        // Create a new blank cursor.
        Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
        cursorImg, new Point(0, 0), "blank cursor");
        // Set the blank cursor to the JFrame.
        frame.getContentPane().setCursor(blankCursor);
        // Compile everything into the frame
        frame.pack();
        // Set frame to close on red exit button
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // Get screen size
        Dimension sSize = Toolkit.getDefaultToolkit().getScreenSize();
        // Position frame
        frame.setLocation(sSize.width / 2 - frame.getWidth(), sSize.height / 2 - frame.getHeight());
        // Make frame visible
        frame.setVisible(true);
        // Set name of frame
        frame.setTitle("Graphical User Interface");
        // While loop to draw oval
        while(true)
        {
            // Repaint the panel 
            panel.repaint();
            // Get mouse info (for tracking)
            info = MouseInfo.getPointerInfo();
            // Set mouse location data to point
            point = info.getLocation();
            // Create variables to store coordinates of oval from mouse point location
            int x = (int) point.getX();
            int y = (int) point.getY();
            // Assign those coordinate variables to oval
            panel.x = x;
            panel.y = y;
//          System.out.println("X: " + x);
//          System.out.println("Y: " + y);
//          System.out.println("X: " + point.getX());
//          System.out.println("Y: " + point.getY());
            // Try-catch to sleep, to reduce some memory
            try
            {
                Thread.sleep(10);
            }
            catch(InterruptedException e)
            {

            }
        }
    }
    // If key is pressed
    public void keyPressed(KeyEvent e) 
    {
        // If key is R, change color and print that key has been pressed
        if (e.getKeyCode() == KeyEvent.VK_R) 
        {
            System.out.println("R");
            panel.red = 255;
            panel.green = 0;
            panel.blue = 0;
        }
        // If key is G, change color and print that key has been pressed
        if (e.getKeyCode() == KeyEvent.VK_G) 
        {
             System.out.println("G");
             panel.red = 0;
             panel.green = 255;
             panel.blue = 0;
        }
        // If key is B, change color and print that key has been pressed
        if (e.getKeyCode() == KeyEvent.VK_B) 
        {
            System.out.println("B");
            panel.red = 0;
            panel.green = 0;
            panel.blue = 255;
        }
    }
    // Doesn't do anything.. yet
    @Override
    public void keyReleased(KeyEvent e) 
    {

    }

    @Override
    public void keyTyped(KeyEvent e) 
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

而且,这是ShapesPanel.java中的代码:

import java.awt.*;
import javax.swing.*;

public class ShapesPanel extends JPanel 
{
    // Create x and y variables, and set as default to zero
    public int x = 0, y = 0;
    // Create RGB variables, used for changing color
    public int red = 0, green = 0, blue = 0;
    private static final long serialVersionUID = 1L;

    // Create new paintComponent function, using an override
    @Override
    public void paintComponent(Graphics g)
    {
        // Create new Graphics2D g2 version
        Graphics2D g2 = (Graphics2D) g;
        // Reset screen, so there are no trails
        g2.clearRect(0, 0, getWidth(), getHeight());
        // Set background, currently unfunctional
//      g2.setBackground(new Color(235, 150, 30));
        // Set color palette, using RGB variables
        g2.setColor(new Color(red, green, blue));
        // Use color palette to draw oval, using x and y variables
        g2.fillOval(x, y, 100, 100);
    }

}
Run Code Online (Sandbox Code Playgroud)

Hov*_*els 6

我有一个静态JPanel,因为我需要它可以在所有函数和方法中访问.

这不是使字段静态的好理由.

但是,Java不允许您使用静态JPanel执行此操作.

这根本不是真的.您可以将KeyListeners或任何其他类似的构造添加到静态和非静态字段中.您的问题与使用静态字段的限制无关.这都是因为你试图thisthis不存在的静态环境中使用.

请注意,您的编译器错误可能会像以下一样简单:

public static ShapesPanel panel = new ShapesPanel().addKeyListener(new Drivers());
Run Code Online (Sandbox Code Playgroud)

我需要JPanel是静态的,所以我可以在keyPressed(KeyEvent e)函数中设置颜色.

这也不是该领域静止的一个很​​好的理由.Swing侦听器可以通过XxxEvent参数的getSource()方法随时随地直接访问侦听组件.例如,如果您使用KeyListener,则其方法的KeyEvent参数有一个getSource()方法,该方法将返回正在侦听的组件(此处为您的绘图JPanel).如果需要引用其他组件或对象,则通过构造函数setter参数将它们传递给侦听器.


  1. 您的主要问题是您尝试this在静态上下文中使用,并且this在此上下文中不存在.
  2. 首先,不要让你的面板字段静止.你说你很熟悉Java,但是给它一个错误的理由让它变得静止.而是将其作为实例字段并在需要的地方传递实例.
  3. 您对此代码有许多其他问题,包括:
    • 你有一个巨大的静态主要方法.这个方法应该小得多,它的工作应该是创建你的程序的关键对象,设置它们运行,就是这样.
    • 你有一个Swing程序,它有一个while (true)和一个Thread.sleep(...)代码,在以后的迭代中(当你更好地构建你的程序并在事件线程上启动了所有Swing代码时)会在Swing事件线程上调用.你会想要摆脱这些家伙,并考虑使用Swing Timer.
    • 你的paintComponent方法不会调用super的方法,打破了Swing绘画链.
    • 使用KeyListener而是使用Key Bindings 会更好.
    • while (true)甚至不需要你的块.不要轮询鼠标的位置,而是使用MouseListener和/或MouseMotionListener.

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;

public class KeyBindingTest {
   // start gui
   private static void createAndShowGui() {
      KeyBindingPanel mainPanel = new KeyBindingPanel();

      JFrame frame = new JFrame("Key Binding Example");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   // start all in a thread safe manner
   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class KeyBindingPanel extends JPanel {
   private static final long serialVersionUID = 1L;
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private static final Color BACKGROUND = Color.WHITE;
   private Color ovalColor = Color.blue;
   private int ovalX = PREF_W / 2;
   private int ovalY = PREF_H / 2;
   private int ovalWidth = 100;

   public KeyBindingPanel() {
      setName("Key Binding Eg");
      setBackground(BACKGROUND);

      final Map<Color, Integer> colorKeyMap = new HashMap<>();
      colorKeyMap.put(Color.BLUE, KeyEvent.VK_B);
      colorKeyMap.put(Color.RED, KeyEvent.VK_R);
      colorKeyMap.put(Color.GREEN, KeyEvent.VK_G);

      // set Key Bindings
      int condition = WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition);
      ActionMap actionMap = getActionMap();

      for (final Color color : colorKeyMap.keySet()) {
         int keyCode = colorKeyMap.get(color);
         KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0);
         inputMap.put(keyStroke, keyStroke.toString());
         actionMap.put(keyStroke.toString(), new ColorAction(color));
      }

      MyMouse myMouse = new MyMouse();
      addMouseMotionListener(myMouse);
   }

   public void setOvalColor(Color color) {
      ovalColor = color;
      repaint();
   }

   public void setOvalPosition(Point p) {
      ovalX = p.x;
      ovalY = p.y;
      repaint();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setColor(ovalColor);
      int x = ovalX - ovalWidth / 2;
      int y = ovalY - ovalWidth / 2;
      g2.fillOval(x, y, ovalWidth, ovalWidth);
   }

   @Override // make panel bigger
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }   
}

class ColorAction extends AbstractAction {
   private static final long serialVersionUID = 1L;
   private Color color;

   public ColorAction(Color color) {
      this.color = color;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      // get reference to bound component
      KeyBindingPanel panel = (KeyBindingPanel) e.getSource();
      panel.setOvalColor(color);
   }
}

class MyMouse extends MouseAdapter {
   @Override
   public void mouseMoved(MouseEvent e) {
      // get reference to listened-to component
      KeyBindingPanel panel = (KeyBindingPanel) e.getSource();
      panel.setOvalPosition(e.getPoint());
   }
}
Run Code Online (Sandbox Code Playgroud)

你可能会问,为什么Map<Color, Integer>在创建Key Bindings时使用a ?

这样做允许我使用for循环来避免代码重复.通常更简洁的代码更容易理解和调试.它还使以后更容易增强程序.例如,如果以后我想添加Color.CYAN并将其与cchar 关联,我所要做的就是在Map中添加另一个条目:

colorKeyMap.put(Color.CYAN, KeyEvent.VK_C);
Run Code Online (Sandbox Code Playgroud)

繁荣,它的完成.如果我需要超过1-1的关联,那么我会考虑使用Enum或单独的类来保存相关的属性.

  • 我可以看到你付出了很多努力来回答这个问题. (2认同)