gpt4 book ai didi

java - 重绘线程不会重绘内部类 JPanel

转载 作者:行者123 更新时间:2023-12-02 00:43:08 25 4
gpt4 key购买 nike

我想在 swing 中制作一个小雨程序,但由于某种原因我无法从另一个类重新绘制面板。这次我尝试使用面板的内部类,但它似乎不适用于从另一个类/线程重新绘制它。有人知道为什么吗?

sscce:

import javax.swing.JPanel;
import javax.swing.Timer;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

public class UI extends JFrame {

public static void main(String[] args) {
UI myProgram = new UI();
myProgram.setVisible(true);
}

public UI() {
this.setSize(new Dimension(500,300));
this.setBackground(Color.WHITE);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
UserPanel p = new UserPanel(this);
}

public class UserPanel extends JPanel implements ActionListener {

private Timer time = new Timer(1, this);
private UI myFrame;

public UserPanel(UI myFrame) {
this.myFrame = myFrame;
this.setSize(myFrame.getSize());

time.start();
}

@Override
public void actionPerformed(ActionEvent e) {
repaint();
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("painting");
g.setColor(Color.BLACK);
g.fillRect(this.getWidth()/2, this.getHeight()/2, 50,50);
}
}
}

UI 类(带有内部类 JPanel):

package Rain;

import javax.swing.JPanel;
import javax.swing.Timer;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;

public class UI extends JFrame {


public UI() {
this.setSize(new Dimension(500,300));
this.setBackground(Color.WHITE);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
UserPanel p = new UserPanel(this);
}


private class UserPanel extends JPanel implements ActionListener {

private Timer time = new Timer(1, this);
private UI myFrame;
private ArrayList<Raindrop> rain = new ArrayList<Raindrop>();
private static final int AMOUNT = 50;
private Random rand = new Random();

public UserPanel(UI myFrame) {
this.myFrame = myFrame;
this.setSize(myFrame.getSize());

for(int i = 0; i < AMOUNT; i++) {
createRain();
}
new Painter(this);
time.start();
}

public void createRain() {
float distance = rand.nextFloat() * 90 + 10;
int x = rand.nextInt(this.getWidth());
int y = 100;

rain.add(new Raindrop(distance,x,y));
}

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("tick");
for(Raindrop r : rain) {
r.fall();
}
}

public void paintComponent(Graphics g) {
System.out.println("painting");
g.setColor(this.getBackground());
g.fillRect(0,0,this.getWidth(),this.getHeight());
for(Raindrop r : rain) {
r.draw(g);
}
}

}

}

画家:

package Rain;

import javax.swing.JPanel;

public class Painter extends Thread {

private JPanel p;

public Painter(JPanel p) {
this.p = p;
this.start();
}

public void run() {
while(true) {
System.out.println("trying to paint..");
p.repaint();
}
}

}

控制台输出:

trying to paint..

tick

trying to paint..

tick

...

预期输出:

trying to paint..

painting

tick

trying to paint..

...

线程确实工作,但它从未调用面板中的paintComponent(Graphics g)函数

最佳答案

所有 Swing 应用程序都必须在自己的线程上运行,称为 EDT 。 (希望您通过调用SwingUtilities#invokelater方法来启动您的应用程序)。因此,在事件调度线程之外重新绘制组件确实是一个糟糕的想法。不要创建新线程,而是在 javax.swing.Timer 的操作监听器中重新绘制组件,因为它将在 EDT 中运行。

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("tick");
for(Raindrop r : rain) {
r.fall();
}
repaint(); //repaint in EDT
}

此外,当您使用 @Override paintComponent 方法时,始终首先调用 super.paintComponent(g);

public void paintComponent(Graphics g) {
super.paintComponent(g);//let component get painted normally
System.out.println("painting");
g.setColor(this.getBackground());
g.fillRect(0,0,this.getWidth(),this.getHeight());
for(Raindrop r : rain) {
r.draw(g);
}
}
<小时/>

SSCCE 后更新

为了绘制组件,它必须有一个父组件。您 UserPanel p = new UserPanel(this); 但您从未将其添加到框架中:

UserPanel p = new UserPanel(this);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(p);

完整的 SSCCE:

public class UI extends JFrame {

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> { //Run in EDT
UI myProgram = new UI();
myProgram.setVisible(true);
});
}

public UI() {
super("title");//call super for frame
this.setSize(new Dimension(500, 300));
this.setBackground(Color.WHITE);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
UserPanel p = new UserPanel(this);

//Use border layout to make p fit the whole frame
getContentPane().setLayout(new BorderLayout());
getContentPane().add(p, BorderLayout.CENTER);
}

public class UserPanel extends JPanel implements ActionListener {

private Timer time = new Timer(1, this);
private UI myFrame;

public UserPanel(UI myFrame) {
this.myFrame = myFrame;
this.setSize(myFrame.getSize());

time.start();
}

@Override
public void actionPerformed(ActionEvent e) {
repaint();
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("painting");
g.setColor(Color.BLACK);
g.fillRect(this.getWidth() / 2, this.getHeight() / 2, 50, 50);
}
}
}

不要忽略SwingUtilities.invokeLater

关于java - 重绘线程不会重绘内部类 JPanel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57920181/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com