我有一个可以自己绘制的9x9网格,一个可以自己绘制的矩形,还有一个允许用方向键移动矩形的构造函数。然而,我想不出如何在矩形移动的同时,让网格在屏幕上保持不变。最终,我希望矩形能够作为网格的导航,当用户按右键时,向右移动一个方格,等等。
据我所知,每当调用paint()时,整个JPanel都会被重做,也就是说,有一种方法是每当有键被按下时,每一行都要重新绘制,但这似乎太过分了。有其他方法吗?就像现在这样,在任何时候画矩形都会导致网格被画过。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestDoubleObject extends JFrame
{
private Color ourRectColor = new Color(28,222,144);
private int ourRectWidth = 50;
private int ourRectHeight = 50;
private Point ourRecLocation = new Point(150,150);
public class Rectangle
{
protected void paint(Graphics2D g2d)
{
g2d.setColor(ourRectColor);
g2d.fillRect(ourRecLocation.x, ourRecLocation.y, ourRectWidth, ourRectHeight);
}
} // Rectangle class
public class OurRectangle extends JPanel
{
private Rectangle capableRectangle;
public OurRectangle()
{
capableRectangle = new Rectangle();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
capableRectangle.paint(g2d);
g2d.dispose();
}
} // OurRectangle class
public class CoreGrid
{
protected void paint(Graphics2D g2d)
{
g2d.setColor(new Color(0,0,0));
// Draw Horizontal Lines
for(int i=100;i<=640;i+=60)
g2d.drawLine(100,i,640,i);
// Draw Vertical Lines
for(int i=100;i<=640;i+=60)
g2d.drawLine(i,100,i,640);
}
} // CoreGrid class
public class OurCoreGrid extends JPanel
{
private CoreGrid capableCoreGrid;
public OurCoreGrid()
{
capableCoreGrid = new CoreGrid();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
capableCoreGrid.paint(g2d);
g2d.dispose();
}
} // OurCoreGrid class
KeyStroke pressRight = KeyStroke.getKeyStroke("RIGHT");
KeyStroke pressLeft = KeyStroke.getKeyStroke("LEFT");
KeyStroke pressUp = KeyStroke.getKeyStroke("UP");
KeyStroke pressDown = KeyStroke.getKeyStroke("DOWN");
OurRectangle recToWorkWith = new OurRectangle();
OurCoreGrid gridToWorkWith = new OurCoreGrid();
public TestDoubleObject()
{
InputMap inputMap = recToWorkWith.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = recToWorkWith.getActionMap();
Action rightAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
ourRecLocation.x += 20;
recToWorkWith.repaint();
}
};
inputMap.put(pressRight, "rightAction");
actionMap.put("rightAction",rightAction);
Action leftAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
ourRecLocation.x -= 20;
recToWorkWith.repaint();
}
};
inputMap.put(pressLeft, "leftAction");
actionMap.put("leftAction",leftAction);
Action downAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
ourRecLocation.y += 20;
recToWorkWith.repaint();
}
};
inputMap.put(pressDown, "downAction");
actionMap.put("downAction",downAction);
Action upAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
ourRecLocation.y -= 20;
recToWorkWith.repaint();
}
};
inputMap.put(pressUp, "upAction");
actionMap.put("upAction",upAction);
add(gridToWorkWith);
add(recToWorkWith);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,800);
setVisible(true);
}
public static void main(String[] argv)
{
EventQueue.invokeLater(
new Runnable()
{
@Override
public void run()
{
new TestDoubleObject();
}
});
}
}
一种方法是每当按下一个键就重新绘制每一行,但这似乎太过分了。
这正是绘画的方式。Swing是双缓冲的,所以你不会注意到绘画问题。
然而,这不是你目前的问题。
我不知道如何在矩形移动的同时保持网格在屏幕上。
JFrame的内容窗格的默认布局管理器是BorderLayout。当你在BorderLayout中添加一个组件,并且没有指定约束条件时,BorderLayout.CENTER被假定为。
add(gridToWorkWith);
add(recToWorkWith);
所以,在上面的代码中,你正试图将两个组件添加到 BorderLayout.CENTER
. 然而只有最后添加的组件才会被BorderLayout管理,这意味着第一个组件的大小将是(0,0),所以它永远不会被绘制。
Swing组件有一个父子关系,所以如果你想让矩形画在网格上面,那么你需要把矩形添加到网格中,就像你把网格添加到框架中一样。
所以代码可能是这样的。
gridToWorkWith.setLayout( new BorderLayout() );
gridToWorkWith.add( recToWorkWith );
add(gridToWorkWith);
//add(recToWorkWith);
但是这仍然不行 因为默认情况下JPanel是不透明的 所以你看不到网格 因为矩形画在了网格上面 所以你需要把矩形做成不透明的。
recToWorkWith.setOpaque( false );
很高兴看到你使用了 "键绑定"。一个建议是创建一个带有参数的Action来控制矩形的移动。所以两个参数将是位置的xy变化。
关于这个方法的例子,请看 MotionAction
见于 MotionWithKeyBindings
例子 使用键盘的运动. 通过使用不同的参数,你的四个Action可以很容易地被替换为4个相同Action的实例。你甚至可以创建一个对角线运动。