我正在尝试创建一个椭圆跟随鼠标光标的简单程序,如果在键盘上输入“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)
{
}
}
而且,这是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);
}
}
答案 0 :(得分:6)
我有一个静态JPanel,因为我需要它可以在所有函数和方法中访问。
这不是使字段静态的好理由。
但是,Java不允许您使用静态JPanel执行此操作。
这根本不是真的。您可以将KeyListeners或任何其他类似的构造添加到静态和非静态字段中。您的问题与使用静态字段的限制无关。这都是因为您尝试在this
不存在的静态上下文中使用this
。
请注意,您的编译器错误可能会像以下一样简单:
public static ShapesPanel panel = new ShapesPanel().addKeyListener(new Drivers());
我需要JPanel是静态的,所以我可以在keyPressed(KeyEvent e)函数中设置颜色。
这再次不是该领域静止的好理由。 Swing侦听器可以通过XxxEvent参数的getSource()
方法随时随地直接访问侦听组件。例如,如果您使用了KeyListener,则其方法的KeyEvent参数具有getSource()
方法,该方法将返回正在侦听的组件(此处为您的绘图JPanel)。如果需要引用其他组件或对象,则通过构造函数setter参数将它们传递给侦听器。
this
,并且在此上下文中不存在this
。 while (true)
和Thread.sleep(...)
,在以后的迭代中(当你更好地构建程序并在事件线程上启动了所有Swing代码时)在Swing事件线程上调用冒险。你会想要摆脱这些家伙,并考虑使用Swing Timer。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());
}
}
您可能会问,为什么在创建密钥绑定时使用Map<Color, Integer>
?
这样做允许我使用for循环来避免代码重复。通常更简洁的代码更容易理解和调试。它还使以后更容易增强程序。例如,如果稍后我想添加Color.CYAN并将其与c
char相关联,那么我所要做的就是在我的Map中添加另一个条目:
colorKeyMap.put(Color.CYAN, KeyEvent.VK_C);
和热潮已经完成了。如果我需要超过1-1的关联,那么我会考虑使用Enum或单独的类来保存相关的属性。