我想重新绘制我的屏幕。到目前为止,它所做的只是在第一个屏幕上的头部应该在的地方显示一个点。这很好,但是我在代码中写了我想每秒将头部向下移动10个像素。我正在打印头部应该在的位置,在命令提示符中它显示y值确实在增加。但是在我的屏幕上,头部没有移动。
我尝试过使用revalidate方法,尝试扩展canvas类而不是jframe,我尝试过只为paint方法使用不同的类,我尝试过用paintComponent方法替换paint方法。正如你可能知道的那样,我对任何与java绘画相关的东西都不太了解。我试着读懂这些超类,但它们太复杂了,我无法理解。我也试过在没有睡眠声明的情况下跑步。这无关紧要。
主类:此类包含开始运行蛇游戏的主方法。
import java.util.concurrent.TimeUnit;
public class Main{
public static void main(String[] args) throws InterruptedException {
Main programma = new Main();
programma.rungame();
}
void rungame() throws InterruptedException {
AllGUIElements gui = new AllGUIElements();
gui.gui();
while (true) {
TimeUnit.SECONDS.sleep(1);
gui.setGameScreen();
}
}
}
AllGUIElements类:该类生成一个新框架,包含一个新面板。正在使用paintComponent对该面板进行喷漆。setGameScreen更新头部的位置,并应重新绘制屏幕。
import javax.swing.*;
import java.awt.*;
public class AllGUIElements extends JPanel {
private JFrame frame;
private JPanel panel;
private int screen;
Snake hoofd = new Head(new Point(30,30),3,null);
void gui() throws InterruptedException {
frame = new JFrame("Snake Game");
panel = new AllGUIElements();
panel.setBackground(Color.GRAY);
panel.setSize(1000,500);
frame.setSize(1000,500);
frame.add(panel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void setGameScreen() {
repaint();
if (hoofd.getDirection() == 1) {
hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y-10));
}
if (hoofd.getDirection() == 2) {
hoofd.setPosition(new Point(hoofd.getPosition().x+10, hoofd.getPosition().y));
}
if (hoofd.getDirection() == 3) {
hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y+10));
}
if (hoofd.getDirection() == 4) {
hoofd.setPosition(new Point(hoofd.getPosition().x-10, hoofd.getPosition().y));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, 1000, 10);
g.fillRect(0, 0, 10, 500);
g.fillRect(990, 0, 10, 500);
g.fillRect(0, 490, 1000, 10);
g.setColor(Color.GREEN);
g.fillRect(hoofd.getPosition().x, hoofd.getPosition().y, 10, 10);
}
}
Screenobject类:蛇和食物的父类(由于没有必要,所以没有发布),返回头部、身体部位和食物的位置。
import java.awt.*;
public class Screenobject{
Point pos;
Screenobject(Point pos){
this.pos = pos;
}
void setPosition(Point pos){
this.pos = pos;
}
Point getPosition() {
return pos;
}
}
蛇类:Screenobject的子类,头部和身体的父类。此类设置对象的方向。
import java.awt.*;
public class Snake extends Screenobject{
int direction;
//directions:
//1 = up
//2 = right
//3 = down
//4 = left
Snake nextpart;
Snake(Point pos, int direction, Snake nextpart){
super(pos);
this.direction = direction;
this.nextpart = nextpart;
}
int getDirection() {
return direction;
}
}
头类:蛇的子类,应该是蛇链接列表的第一个对象。
import java.awt.*;
public class Head extends Snake{
Head(Point pos, int direction, Snake nextpart){
super(pos, direction, nextpart);
}
}
身体类:蛇的子类,每吃一种食物就会生长。
import java.awt.*;
public class Body extends Snake{
Body(Point pos, int direction, Snake nextpart){
super(pos, direction, nextpart);
}
}
第一件事:
我使用“分而治之”的方法只发布必要的信息
是的,您只发布了必要的信息,但您仍然为MCVE/MRE使用了太多的类,理想情况下,您的所有代码都适合一个类。
我没能在不省略代码的情况下将其缩短。
这就是我们要求MRE的想法,你应该创建一个全新的程序来隔离问题,在你的情况下,这是:在某个方向上移动一个形状,并继续朝那个方向移动。
现在,我可以看到你已经尝试创建它,并加以改进,所以我将发布一个例子,说明你未来的问题中需要什么,以便你在未来提出更好的问题。
话虽如此,让我们去回答你的问题。
这是一个不到100行代码(不包括注释)的示例,它解决了代码中的以下问题:
>
删除while(true)
语句以支持Swing Timer以防止阻塞事件调度线程(EDT)
将程序放在EDT上,参见本答案的第2点
使用JFrame#pack()
方法,而不是使用setSize(...)
为JFrame
和JBoard
手动设置它
去掉方向的“幻数”,并为此使用枚举,因此代码更可读,因为我们都知道顶部应该移动到顶部,但我们不知道1应该移动到顶部。
使用图形API在JPanel上绘制图形,如本答案所示
我还建议您使用camelCase来命名方法,这样,与其他方法一样,rungame()
变得更易于阅读。给他们起个更有意义的名字,比如hoofd,我不知道那是什么,如果我没有语境单独阅读,就很难说出它是什么类型的物体。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SnakeGame {
private JFrame frame;
private Snake snake;
private JPanel buttonsPane;
private JButton[] buttons; // Our array of buttons
private Timer timer;
private Direction currentDirection;
// This enum will be used to determine the direction the snake will take.
private enum Direction {
TOP, LEFT, BOTTOM, RIGHT
}
public static void main(String[] args) {
// We place our program on the EDT using Java 8 lambda expressions.
SwingUtilities.invokeLater(() -> new SnakeGame().createAndShowGUI());
}
private void createAndShowGUI() {
frame = new JFrame(getClass().getSimpleName());
snake = new Snake();
buttonsPane = new JPanel();
buttons = new JButton[Direction.values().length];
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton(Direction.values()[i].toString()); // We create a JButton with the current value of the direction
buttons[i].addActionListener(listener); // We set their ActionListeners
buttonsPane.add(buttons[i]); // And add them to the buttonsPane
}
currentDirection = Direction.RIGHT; // We set a default direction
timer = new Timer(1000, listener); // And start our Swing Timer
// We add our components and then pack the frame, after that we start the timer.
frame.add(snake);
frame.add(buttonsPane, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
timer.start();
}
// Our ActionListener for moving the snake
private ActionListener listener = e -> { // Using Java 8 lambda expressions again
// We set the current direction using a ternary, if the source of the event is
// the timer we leave the current direction as is
// otherwise we set it to the direction from the button clicked
currentDirection = e.getSource().equals(timer) ? currentDirection : Direction.valueOf(e.getActionCommand());
snake.move(currentDirection); // And we call the move method
};
@SuppressWarnings("serial")
class Snake extends JPanel {
private int xPos;
private int yPos;
private static final int SPEED = 10; // We set the speed as a constant (10 pixels at a time) in any direction
// We determine the movement direction
public void move(Direction direction) {
switch (direction) {
case TOP:
yPos -= SPEED;
break;
case LEFT:
xPos -= SPEED;
break;
case BOTTOM:
yPos += SPEED;
break;
case RIGHT:
xPos += SPEED;
break;
}
this.repaint(); // And repaint the snake
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.DARK_GRAY);
g2d.fill(new Rectangle2D.Double(xPos, yPos, 10, 10)); // We draw a rectangle using the Shape API
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300); // We set the preferredSize of the JPanel to 300 x 300
}
}
}
以上代码生成以下结果,对于Java 7及以下版本,或者如果您不想使用lambda表达式或对您来说太难,请检查此答案上的第2点,它显示了如何在没有lambda表达式的情况下将程序放置在EDT上,此答案还显示了如何在没有lambda表达式的情况下编写ActionListener。
好了,一个简单的可运行示例,它是完整的、可验证的、最小的,这就是我们在未来的问题中对您的期望。
https://imgs.xnip.cn/cj/n/18/85a0abe9-7bf6-4f3c-8cda-6bc819bb9a69.gif" width="100%" height="100%" />
编辑:当我拖动边框时,某种刷新被发送,我需要弄清楚并手动发送相同的刷新。 请注意,我已经尝试使用revalidate()和repaint()。 当使用JFrame和JPanel来显示一个框架时,我试图使框架的大小易于改变。 null 此外,一个重要的注意事项是,当您拖动边框时,白条会消失,并正确地重新加载/刷新内容(即使您只是少量拖动)
在用JFrame编写一个简单的Tron游戏时,我遇到了一点问题。我不确定我如何能保持显示为“光循环”作为一条线停留在屏幕上显示,但同时重新油漆屏幕,使移动仍然有效。以下是我的代码:(仅供参考,它全部编译,所有工作都像它在这里写的一样完美) 另外,我想知道,当我按下一个箭头键时,它将如何使它,而不是只从x或y键中添加或减去一次,而是不断地添加到x或y键,直到按下另一个箭头。 顺便说一句,如果有人想知
问题内容: 我是Java的初学者,我正在尝试创建一个在光标所在的位置绘制一个矩形的应用程序。我已经完成了所有操作,但无法获得重绘的信息。如果没有重绘,则矩形仅绘制一次,仅此而已。使用重新绘制,它可以很好地编译,但是当我运行它时,每次移动鼠标时,都会出现这个大错误。 所以,有人可以帮我吗? 问题答案: 希望代码示例中的注释能够告诉您您在代码中做错了什么:-),否则总有理由提出您的疑问…
问题内容: 我在程序开始时,根据数据库中的某些内容,以编程方式在JScrollPane中添加了许多组件(JPanels,JLabels等)。 似乎对于GUI(?)而言,此过程太快了,因此JScrollPane并不总是正确更新,即,即使内部JPanel大于可见区域,滚动条也不可见。 调整窗口大小(JFrame)可以解决此问题,因为我认为Java在调整组件大小时会重新打印它们。 作为测试,我添加了一个
我有一个正在添加JLabel的JPanel。然后我想删除所有的JLabel并添加一些新的。 所以我做了以下几点: 这很好。当我在这之后开始一个新线程时,我的问题就出现了,比如: 然后原始JLabels的输出仍然可见。我读到重新验证过程是一个长时间运行的任务,因此firstProducer线程正在启动,而重新验证正在进行并产生冲突。处理这个问题的最佳方法是什么?
我试图在if语句中设置状态,但它不会这样做。结果,我需要从if语句中更新状态,在那个里我可以接收经度和纬度坐标,但它不会保存状态。若我在If语句之外的控制台中回显,我将只读取第一个setState值表单componentWillMount。有什么问题吗?我做错了什么?结构如下: