repaint() 方法不重绘 JPanel
repaint() Method Not Repainting JPanel
好的,所以首先我知道还有很多关于这个问题的其他线程,但他们只说尝试使用对我没有影响的 invalidate() 和 validate()。
我的问题是——正如标题所表明的那样——JPanel 的 repaint() 方法没有重新绘制。我在 paintComponent() 方法中添加了一些调试消息,控制台输出如下:
Debug
-10 421 010 441
repainted
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
请注意,在程序开始时您只看到 debug
、(co-ordinates)
和 repainted
一次,但我调用了 repaint();每次移动鼠标。
我将我的五个 类 合二为一,因为我认为它是调试目的的首选:
package com.trtld.spacewar;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GroupClass {
private static Content content = new Content();
public static void main(String[] args) {
JFrame window = new JFrame("Spacewar!");
content.setVisible(true);
window.setContentPane(content);
MouseInput listener = new MouseInput();
content.addMouseMotionListener(listener);
content.addMouseListener(listener);
window.setSize(600, 480);
window.setLocation(100, 100);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
//window.setResizable(false);
System.out.println("Debug");
}
}
class Target {
private int x1, y1;
private int x2, y2;
public Target(int x1, int y1, int x2, int y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public int getX1(){
return x1;
}
public int getX2(){
return x2;
}
public int getY1(){
return y1;
}
public int getY2(){
return y2;
}
}
class Content extends JPanel{
private static Content instance;
private Target[] targets = new Target[9];
private Bullet[] bullets = new Bullet[999];//assuming no more than 1000 bullets are on the screen at
//once (they'd have to have a really fancy-nice auto-clicker ha ha)
int spaceShipX = (getWidth()/2);
public Content (){
int yLevel = (((int)Math.random())*(getHeight() / 4));
int xPos = ((int)Math.random())*getWidth();
for(int i = 0;!(i == 9); i++){ //Create the randomly located targets
targets[i] = new Target(xPos, yLevel, xPos-15, yLevel-10);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
System.out.println(spaceShipX-10 + " " + (getHeight()-20) + " " + spaceShipX+10 + " " + getHeight());
System.out.println("repainted");
g.fillRect(spaceShipX+50, getHeight()-20 ,spaceShipX+100 , getHeight());
/** //commented out for simplicity + needs to be fixed:
for(Target t : this.targets){ //paint targets
g.drawRect(t.getX1(), t.getY1(), t.getX2(), t.getY2());
}
for(Bullet b : this.bullets){ //paint bullets and remove invalid ones plus check for hits
if(b != null){
g.drawRect(b.getX1(), b.getY1(), b.getX2(), b.getY2());
if(!(b.checkTargetPresence() == null)){
for(Target target : targets){
if(b.checkTargetPresence() == target){
target = null;
}
}
}
if(b.isValid() == false){
b = null;
}
}
}*/
}
public static Content getInstance(){
if(instance == null) {
instance = new Content(); //TODO: Singletons are out-dated and not preferred; fix this
}
return instance;
}
//Getters and setters:
public Bullet[] getBullets(){
return bullets;
}
public Target[] getTargets(){
return targets;
}
public void setTarget(Target t, int loc){
this.targets[loc] = t;
}
public void setBullet(Bullet b){
int location = -1;
if(bullets[0] == null){
this.bullets[0] = b;
return;
}
for(Bullet bullet: bullets){
location++;
if(bullets[location] == null){ //TODO: Messy, clean this up
bullets[location] = b;
return;
}
}
}
public int getSpaceShipX(){
return spaceShipX;
}
public void setSpaceShipX(int x){
spaceShipX = x-10;
repaint();
}
}
class Bullet implements ActionListener{
int x1, x2;
int y1 = 10, y2 = 5;
Timer timer = new Timer(250, this);
public Bullet(int x1, int x2){
this.x1 = x1;
this.x2 = x2;
timer.start();
}
public void actionPerformed(ActionEvent evt) {
y1 = y1 + 2;
y2 += 2;
Content.getInstance().repaint();
}
public Target checkTargetPresence(){
for(Target t : Content.getInstance().getTargets()){
if(x1 <= t.getX1() && x1 >= t.getX2()){
if(y1 <= t.getY1() && y1 >= t.getY2()){
//HIT!
return t;
}
}
}
return null; //TODO
}
public boolean isValid(){//Checks if the bullet is still on the screen
if(y1 >= Content.getInstance().getHeight() || y2 >= Content.getInstance().getHeight()){
return false;
}else{
return true;
}
}
public int getX1(){
return x1;
}
public int getX2(){
return x2;
}
public int getY1(){
return y1;
}
public int getY2(){
return y2;
}
}
class MouseInput implements MouseListener, MouseMotionListener {
public void mouseDragged(MouseEvent arg0) {
}
public void mouseMoved(MouseEvent evt) {
Content.getInstance().setSpaceShipX(evt.getX());
Content.getInstance().repaint(); // I try to repaint here and in the Content class, but nothing happens.
System.out.println("Moved mouse");
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent evt) {
Content.getInstance().setBullet(new Bullet(evt.getX()-2, evt.getX()+2));
System.out.println("clicked");
}
public void mouseReleased(MouseEvent arg0) {
}
}
非常感谢任何帮助,如果我需要以不同的方式设置格式,请告诉我。
请注意,这是我的第一个 GUI 程序。
我认为问题在于您创建了内容 class 然后将其添加到框架中。
但是,在您的 MouseListener 代码中,您调用了 Content class 的 getInstance()
方法并且 "instance" 变量为空,因此创建了一个新的 Content 实例(但从未添加到框架,因此它永远不会被涂漆)。
所以这个基本逻辑是错误的,你不想创建一个新实例。
而不是在你的内容的构造函数中 class 你会这样做:
instance = this;
然后 getInstance() 方法将只是 return 变量,因为它总是有一个值。
另外,MouseListeners 应该在您的内容 class 的内部 class。也就是说,您应该创建侦听器并将其添加到您的 class。当你这样做时,你甚至不需要静态 getInstance() 方法,因为你可以直接访问实例变量。
but they only say to try using invalidate() and validate() which had no effect for me.
你不应该使用那些方法。这些在 AWT 中使用。在 Swing 中,您可以使用:
revalidate();
repaint();
当您在 GUI 可见后向 GUI 添加组件时,或者当您在自定义 class 中更改 属性 时。 revalidate() 将调用布局管理器。 repaint() 将绘制组件。在你的 class 中,你没有改变任何东西的大小,所以你只需要在 setter 方法中使用 repaint() 。
编辑:
Mind sharing the code you added?
我添加了一行代码:
public Content (){
int yLevel = (((int)Math.random())*(getHeight() / 4));
int xPos = ((int)Math.random())*getWidth();
for(int i = 0;!(i == 9); i++) {
//Create the randomly located targets
targets[i] = new Target(xPos, yLevel, xPos-15, yLevel-10);
}
instance = this; // added
}
一次进行一项更改。一旦您通过添加单行代码验证了我的假设是有效的。然后就可以收拾剩下的class了。如果您一次进行多项更改,您将不知道是哪一项导致了问题。
好的,所以首先我知道还有很多关于这个问题的其他线程,但他们只说尝试使用对我没有影响的 invalidate() 和 validate()。
我的问题是——正如标题所表明的那样——JPanel 的 repaint() 方法没有重新绘制。我在 paintComponent() 方法中添加了一些调试消息,控制台输出如下:
Debug
-10 421 010 441
repainted
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
请注意,在程序开始时您只看到 debug
、(co-ordinates)
和 repainted
一次,但我调用了 repaint();每次移动鼠标。
我将我的五个 类 合二为一,因为我认为它是调试目的的首选:
package com.trtld.spacewar;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GroupClass {
private static Content content = new Content();
public static void main(String[] args) {
JFrame window = new JFrame("Spacewar!");
content.setVisible(true);
window.setContentPane(content);
MouseInput listener = new MouseInput();
content.addMouseMotionListener(listener);
content.addMouseListener(listener);
window.setSize(600, 480);
window.setLocation(100, 100);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
//window.setResizable(false);
System.out.println("Debug");
}
}
class Target {
private int x1, y1;
private int x2, y2;
public Target(int x1, int y1, int x2, int y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public int getX1(){
return x1;
}
public int getX2(){
return x2;
}
public int getY1(){
return y1;
}
public int getY2(){
return y2;
}
}
class Content extends JPanel{
private static Content instance;
private Target[] targets = new Target[9];
private Bullet[] bullets = new Bullet[999];//assuming no more than 1000 bullets are on the screen at
//once (they'd have to have a really fancy-nice auto-clicker ha ha)
int spaceShipX = (getWidth()/2);
public Content (){
int yLevel = (((int)Math.random())*(getHeight() / 4));
int xPos = ((int)Math.random())*getWidth();
for(int i = 0;!(i == 9); i++){ //Create the randomly located targets
targets[i] = new Target(xPos, yLevel, xPos-15, yLevel-10);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
System.out.println(spaceShipX-10 + " " + (getHeight()-20) + " " + spaceShipX+10 + " " + getHeight());
System.out.println("repainted");
g.fillRect(spaceShipX+50, getHeight()-20 ,spaceShipX+100 , getHeight());
/** //commented out for simplicity + needs to be fixed:
for(Target t : this.targets){ //paint targets
g.drawRect(t.getX1(), t.getY1(), t.getX2(), t.getY2());
}
for(Bullet b : this.bullets){ //paint bullets and remove invalid ones plus check for hits
if(b != null){
g.drawRect(b.getX1(), b.getY1(), b.getX2(), b.getY2());
if(!(b.checkTargetPresence() == null)){
for(Target target : targets){
if(b.checkTargetPresence() == target){
target = null;
}
}
}
if(b.isValid() == false){
b = null;
}
}
}*/
}
public static Content getInstance(){
if(instance == null) {
instance = new Content(); //TODO: Singletons are out-dated and not preferred; fix this
}
return instance;
}
//Getters and setters:
public Bullet[] getBullets(){
return bullets;
}
public Target[] getTargets(){
return targets;
}
public void setTarget(Target t, int loc){
this.targets[loc] = t;
}
public void setBullet(Bullet b){
int location = -1;
if(bullets[0] == null){
this.bullets[0] = b;
return;
}
for(Bullet bullet: bullets){
location++;
if(bullets[location] == null){ //TODO: Messy, clean this up
bullets[location] = b;
return;
}
}
}
public int getSpaceShipX(){
return spaceShipX;
}
public void setSpaceShipX(int x){
spaceShipX = x-10;
repaint();
}
}
class Bullet implements ActionListener{
int x1, x2;
int y1 = 10, y2 = 5;
Timer timer = new Timer(250, this);
public Bullet(int x1, int x2){
this.x1 = x1;
this.x2 = x2;
timer.start();
}
public void actionPerformed(ActionEvent evt) {
y1 = y1 + 2;
y2 += 2;
Content.getInstance().repaint();
}
public Target checkTargetPresence(){
for(Target t : Content.getInstance().getTargets()){
if(x1 <= t.getX1() && x1 >= t.getX2()){
if(y1 <= t.getY1() && y1 >= t.getY2()){
//HIT!
return t;
}
}
}
return null; //TODO
}
public boolean isValid(){//Checks if the bullet is still on the screen
if(y1 >= Content.getInstance().getHeight() || y2 >= Content.getInstance().getHeight()){
return false;
}else{
return true;
}
}
public int getX1(){
return x1;
}
public int getX2(){
return x2;
}
public int getY1(){
return y1;
}
public int getY2(){
return y2;
}
}
class MouseInput implements MouseListener, MouseMotionListener {
public void mouseDragged(MouseEvent arg0) {
}
public void mouseMoved(MouseEvent evt) {
Content.getInstance().setSpaceShipX(evt.getX());
Content.getInstance().repaint(); // I try to repaint here and in the Content class, but nothing happens.
System.out.println("Moved mouse");
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent evt) {
Content.getInstance().setBullet(new Bullet(evt.getX()-2, evt.getX()+2));
System.out.println("clicked");
}
public void mouseReleased(MouseEvent arg0) {
}
}
非常感谢任何帮助,如果我需要以不同的方式设置格式,请告诉我。 请注意,这是我的第一个 GUI 程序。
我认为问题在于您创建了内容 class 然后将其添加到框架中。
但是,在您的 MouseListener 代码中,您调用了 Content class 的 getInstance()
方法并且 "instance" 变量为空,因此创建了一个新的 Content 实例(但从未添加到框架,因此它永远不会被涂漆)。
所以这个基本逻辑是错误的,你不想创建一个新实例。
而不是在你的内容的构造函数中 class 你会这样做:
instance = this;
然后 getInstance() 方法将只是 return 变量,因为它总是有一个值。
另外,MouseListeners 应该在您的内容 class 的内部 class。也就是说,您应该创建侦听器并将其添加到您的 class。当你这样做时,你甚至不需要静态 getInstance() 方法,因为你可以直接访问实例变量。
but they only say to try using invalidate() and validate() which had no effect for me.
你不应该使用那些方法。这些在 AWT 中使用。在 Swing 中,您可以使用:
revalidate();
repaint();
当您在 GUI 可见后向 GUI 添加组件时,或者当您在自定义 class 中更改 属性 时。 revalidate() 将调用布局管理器。 repaint() 将绘制组件。在你的 class 中,你没有改变任何东西的大小,所以你只需要在 setter 方法中使用 repaint() 。
编辑:
Mind sharing the code you added?
我添加了一行代码:
public Content (){
int yLevel = (((int)Math.random())*(getHeight() / 4));
int xPos = ((int)Math.random())*getWidth();
for(int i = 0;!(i == 9); i++) {
//Create the randomly located targets
targets[i] = new Target(xPos, yLevel, xPos-15, yLevel-10);
}
instance = this; // added
}
一次进行一项更改。一旦您通过添加单行代码验证了我的假设是有效的。然后就可以收拾剩下的class了。如果您一次进行多项更改,您将不知道是哪一项导致了问题。