不能将 .addKeyListener(this) 用于静态 JPanel,但需要 JPanel 保持静态 - Java
Can't Use .addKeyListener(this) for a static JPanel, but need the JPanel to stay static - Java
我正在尝试制作一个简单的程序,其中椭圆形跟随鼠标光标,如果您在键盘上输入 "r"、"g" 或 "b",椭圆形会发生变化相应地着色。
但是,我无法让我的 KeyListener 工作。这是我的问题。我有一个静态 JPanel,因为我需要它可以在所有函数和方法中访问。但是,Java 不允许您使用静态 JPanel 执行此操作。我需要 JPanel 是静态的,这样我就可以在 keyPressed(KeyEvent e) 函数中设置颜色。
我对 Java 的基础知识了解得很好,并且正在掌握一些更复杂的概念。请尝试解释是否有任何复杂的代码。谢谢!
这里是Drivers.java里的代码,主要class.
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)
{
}
}
并且,这是 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);
}
}
I have a static JPanel, because I need it to be accessible in all functions and methods.
这不是将字段设为静态的好理由。
However, Java does not let you do this with a static JPanel.
这根本不是真的。您可以轻松地将 KeyListeners 或任何其他类似构造添加到静态和非静态字段。您的问题与静态字段的使用限制无关。这都是因为您试图在 this
不存在的静态上下文中使用 this
。
请注意,您的编译器错误可能会随着以下简单内容而消失:
public static ShapesPanel panel = new ShapesPanel().addKeyListener(new Drivers());
I need the JPanel to be static so I can set the color in the keyPressed(KeyEvent e) function.
这又不是该字段为静态的好理由。 Swing 侦听器可以随时通过 XxxEvent 参数的 getSource()
方法直接访问被侦听的组件。例如,如果您使用了 KeyListener,则其方法的 KeyEvent 参数有一个 getSource()
方法,该方法将 return 正在监听的组件(这里是您的绘图 JPanel)。如果您需要对其他组件或对象的引用,则通过构造函数 setter 参数将它们传递给侦听器。
- 您的主要问题是您试图在静态上下文中使用
this
,而 this
在此上下文中不存在。
- 第一件事是不要让你的面板字段静态化。您声明您非常了解 Java,但随后给出了使其成为静态的错误理由。而是将其设为实例字段并在需要的地方传递实例。
- 此代码还有许多其他问题,包括:
- 您有一个巨大的静态 main 方法。这个方法应该小得多,它的工作应该是创建程序的关键对象,设置它们 运行 就是这样。
- 你有一个 Swing 程序,它在代码中有一个
while (true)
和一个 Thread.sleep(...)
,在以后的迭代中(当你更好地构建你的程序并在事件上启动所有 Swing 代码时thread) 在 Swing 事件线程上被调用的风险。你会想要摆脱这些家伙,并考虑改用 Swing Timer。
- 您的 paintComponent 方法没有调用 super 的方法,破坏了 Swing 绘画链。
- 您最好不 使用 KeyListener 而是使用键绑定。
- 甚至不需要您的
while (true)
块。不要轮询鼠标的位置,而是为此使用 MouseListener and/or 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());
}
}
您可能会问,为什么在创建键绑定时使用 Map<Color, Integer>
?
这样做可以让我使用 for 循环来避免代码重复。通常更简洁的代码更容易理解和调试。它还使以后更容易增强程序。例如,如果稍后我想添加 Color.CYAN 并将其与 c
字符相关联,我所要做的就是向我的 Map 添加另一个条目:
colorKeyMap.put(Color.CYAN, KeyEvent.VK_C);
和boom它完成了。如果我需要的不仅仅是 1-1 关联,那么我会考虑使用枚举或单独的 class 将相关属性放在一起。
我正在尝试制作一个简单的程序,其中椭圆形跟随鼠标光标,如果您在键盘上输入 "r"、"g" 或 "b",椭圆形会发生变化相应地着色。
但是,我无法让我的 KeyListener 工作。这是我的问题。我有一个静态 JPanel,因为我需要它可以在所有函数和方法中访问。但是,Java 不允许您使用静态 JPanel 执行此操作。我需要 JPanel 是静态的,这样我就可以在 keyPressed(KeyEvent e) 函数中设置颜色。
我对 Java 的基础知识了解得很好,并且正在掌握一些更复杂的概念。请尝试解释是否有任何复杂的代码。谢谢!
这里是Drivers.java里的代码,主要class.
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)
{
}
}
并且,这是 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);
}
}
I have a static JPanel, because I need it to be accessible in all functions and methods.
这不是将字段设为静态的好理由。
However, Java does not let you do this with a static JPanel.
这根本不是真的。您可以轻松地将 KeyListeners 或任何其他类似构造添加到静态和非静态字段。您的问题与静态字段的使用限制无关。这都是因为您试图在 this
不存在的静态上下文中使用 this
。
请注意,您的编译器错误可能会随着以下简单内容而消失:
public static ShapesPanel panel = new ShapesPanel().addKeyListener(new Drivers());
I need the JPanel to be static so I can set the color in the keyPressed(KeyEvent e) function.
这又不是该字段为静态的好理由。 Swing 侦听器可以随时通过 XxxEvent 参数的 getSource()
方法直接访问被侦听的组件。例如,如果您使用了 KeyListener,则其方法的 KeyEvent 参数有一个 getSource()
方法,该方法将 return 正在监听的组件(这里是您的绘图 JPanel)。如果您需要对其他组件或对象的引用,则通过构造函数 setter 参数将它们传递给侦听器。
- 您的主要问题是您试图在静态上下文中使用
this
,而this
在此上下文中不存在。 - 第一件事是不要让你的面板字段静态化。您声明您非常了解 Java,但随后给出了使其成为静态的错误理由。而是将其设为实例字段并在需要的地方传递实例。
- 此代码还有许多其他问题,包括:
- 您有一个巨大的静态 main 方法。这个方法应该小得多,它的工作应该是创建程序的关键对象,设置它们 运行 就是这样。
- 你有一个 Swing 程序,它在代码中有一个
while (true)
和一个Thread.sleep(...)
,在以后的迭代中(当你更好地构建你的程序并在事件上启动所有 Swing 代码时thread) 在 Swing 事件线程上被调用的风险。你会想要摆脱这些家伙,并考虑改用 Swing Timer。 - 您的 paintComponent 方法没有调用 super 的方法,破坏了 Swing 绘画链。
- 您最好不 使用 KeyListener 而是使用键绑定。
- 甚至不需要您的
while (true)
块。不要轮询鼠标的位置,而是为此使用 MouseListener and/or 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());
}
}
您可能会问,为什么在创建键绑定时使用 Map<Color, Integer>
?
这样做可以让我使用 for 循环来避免代码重复。通常更简洁的代码更容易理解和调试。它还使以后更容易增强程序。例如,如果稍后我想添加 Color.CYAN 并将其与 c
字符相关联,我所要做的就是向我的 Map 添加另一个条目:
colorKeyMap.put(Color.CYAN, KeyEvent.VK_C);
和boom它完成了。如果我需要的不仅仅是 1-1 关联,那么我会考虑使用枚举或单独的 class 将相关属性放在一起。