我正在制作這個程式,其中由用戶控制的 JLabel 將在 500x500 幀上移動,但由于某種原因,它似乎有兩個位置,當它移動時它只是在它們之間閃爍。這是什么原因造成的?
這就是它目前的樣子
這是主視窗:
package guipkg1;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import guipkg1.PlayerMove;
public class KeyListenerPage extends JFrame implements KeyListener {
public static JLabel player = new JLabel();
public static boolean isGoingLeft = false;
public static boolean isGoingUp = false;
public static boolean isGoingRight = false;
public static boolean isGoingDown = false;
PlayerMove pmove = new PlayerMove();
KeyListenerPage(){
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
this.setSize(500,500);
this.setLayout(null);
this.setVisible(false);
this.addKeyListener(this);
player.setBounds(0,0,50,50);
player.setText(":)");
this.add(player);
pmove.start();
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode()==37 || e.getKeyCode()==65) {
isGoingLeft = true;
System.out.println("[KeyListenerPage] going left");
} else if(e.getKeyCode()==38 || e.getKeyCode()==87) {
isGoingUp = true;
System.out.println("[KeyListenerPage] going up");
} else if(e.getKeyCode()==39 || e.getKeyCode()==68) {
isGoingRight = true;
System.out.println("[KeyListenerPage] going right");
} else if(e.getKeyCode()==40 || e.getKeyCode()==83) {
isGoingDown = true;
System.out.println("[KeyListenerPage] going down");
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode()==37 || e.getKeyCode()==65) {
isGoingLeft = false;
System.out.println("[KeyListenerPage] stopped going left");
} else if(e.getKeyCode()==38 || e.getKeyCode()==87) {
isGoingUp = false;
System.out.println("[KeyListenerPage] stopped going up");
} else if(e.getKeyCode()==39 || e.getKeyCode()==68) {
isGoingRight = false;
System.out.println("[KeyListenerPage] stopped going right");
} else if(e.getKeyCode()==40 || e.getKeyCode()==83) {
isGoingDown = false;
System.out.println("[KeyListenerPage] stopped going down");
}
}
}
以及移動播放器的執行緒:
package guipkg1;
import javax.swing.JLabel;
public class PlayerMove extends Thread implements Runnable {
boolean movingLeft = KeyListenerPage.isGoingLeft;
boolean movingUp = KeyListenerPage.isGoingUp;
boolean movingRight = KeyListenerPage.isGoingRight;
boolean movingDown = KeyListenerPage.isGoingDown;
JLabel player = KeyListenerPage.player;
boolean canMoveLeft = false;
boolean canMoveRight = true;
boolean canMoveUp = false;
boolean canMoveDown = true;
public void run() {
System.out.println("running");
while(true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
movingLeft = KeyListenerPage.isGoingLeft;
movingUp = KeyListenerPage.isGoingUp;
movingRight = KeyListenerPage.isGoingRight;
movingDown = KeyListenerPage.isGoingDown;
if(movingLeft && canMoveLeft) {
player.setBounds(player.getWidth(), player.getHeight(), player.getX()-10, player.getY());
player.setVisible(true);
if(player.getX()<=0) {
canMoveLeft = false;
}
if(player.getX()<490) {
canMoveRight = true;
}
}
if(movingRight && canMoveRight) {
player.setBounds(player.getWidth(), player.getHeight(), player.getX() 10, player.getY());
player.setVisible(true);
if(player.getX()>0) {
canMoveLeft = true;
}
if(player.getX()>=490) {
canMoveRight = false;
}
}
if(movingUp && canMoveUp) {
player.setBounds(player.getWidth(), player.getHeight(), player.getX(), player.getY()-10);
player.setVisible(true);
if(player.getY()<=0) {
canMoveUp = false;
}
if(player.getY()<490) {
canMoveDown = true;
}
}
if(movingDown && canMoveDown) {
player.setBounds(player.getWidth(), player.getHeight(), player.getX(), player.getY() 10);
player.setVisible(true);
if(player.getY()>0) {
canMoveUp = true;
}
if(player.getY()>=490) {
canMoveDown = false;
}
}
}
}
}
uj5u.com熱心網友回復:
為什么會閃爍?
因為您的論點player.setBounds()順序錯誤。
根據JLabel#setBounds() JavaDoc,引數的順序是x, y, width, height。
但是您的代碼使用引數呼叫該方法
player.setBounds(player.getWidth(), player.getHeight(), player.getX(), player.getY() 10);
它應該在哪里
player.setBounds(player.getX(), player.getY() 10, player.getWidth(), player.getHeight());
另請注意,Swing 不是執行緒安全的。如果要更改顯示的 Swing 組件上的任何內容,則必須在 Swing EDT 上進行,例如重寫PlayerMove.run()為
public void run() {
System.out.println("running");
while(true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(this::move);
}
}
并將剩余的代碼PlayerMove.run()移到一個新move()方法中:
private void move() {
movingLeft = KeyListenerPage.isGoingLeft;
movingUp = KeyListenerPage.isGoingUp;
movingRight = KeyListenerPage.isGoingRight;
movingDown = KeyListenerPage.isGoingDown;
if(movingLeft && canMoveLeft) {
player.setBounds(player.getX()-10, player.getY(), player.getWidth(), player.getHeight());
player.setVisible(true);
if(player.getX()<=0) {
canMoveLeft = false;
}
if(player.getX()<490) {
canMoveRight = true;
}
}
if(movingRight && canMoveRight) {
player.setBounds(player.getX() 10, player.getY(), player.getWidth(), player.getHeight());
player.setVisible(true);
if(player.getX()>0) {
canMoveLeft = true;
}
if(player.getX()>=490) {
canMoveRight = false;
}
}
if(movingUp && canMoveUp) {
player.setBounds(player.getX(), player.getY()-10, player.getWidth(), player.getHeight());
player.setVisible(true);
if(player.getY()<=0) {
canMoveUp = false;
}
if(player.getY()<490) {
canMoveDown = true;
}
}
if(movingDown && canMoveDown) {
player.setBounds(player.getX(), player.getY() 10, player.getWidth(), player.getHeight());
player.setVisible(true);
if(player.getY()>0) {
canMoveUp = true;
}
if(player.getY()>=490) {
canMoveDown = false;
}
}
}
請注意,此解決方案仍然適用于單獨的執行緒(即仍然PlayerMove擴展Thread并且您仍然必須呼叫pmove.start();)KeyListenerPage
正如 MadProgrammer 已經評論過的,更好的方法是使用 Swing Timer
這樣的解決方案會稍微改變您的代碼。
該類PlayerMove將更改為
public class PlayerMove implements ActionListener {
boolean movingLeft = false;
boolean movingUp = false;
boolean movingRight = false;
boolean movingDown = false;
JLabel player = KeyListenerPage.player;
boolean canMoveLeft = false;
boolean canMoveRight = true;
boolean canMoveUp = false;
boolean canMoveDown = true;
@Override
public void actionPerformed(ActionEvent e) {
// here is all the moving code,
// i.e. what in your solution was in the run() method
// but without the looping
// The Timer will call this every 20ms for you
}
}
在KeyListenerPage()建構式中,您將替換
pmove.start();
和
Timer timer = new Timer(20, pmove);
timer.start();
您的代碼中不再需要“永無止境的回圈” -Timer現在需要注意pmove.actionPerformed()每 20 毫秒呼叫一次。
這段代碼:
public void run() {
System.out.println("running");
while(true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(this::move);
}
}
可以通過用move()方法替換方法來完全洗掉actionPerformed()(方法中的代碼不需要更改!)并pmove.start();用兩行替換 - 恕我直言,這是一個明顯的改進。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/429895.html
