Java 重涂螺纹不';t重新绘制内部类JPanel

Java 重涂螺纹不';t重新绘制内部类JPanel,java,swing,repaint,Java,Swing,Repaint,我想在swing中制作一个小的rain程序,但由于某些原因,我无法从另一个类中重新绘制面板。这次我尝试为面板使用一个内部类,但它似乎无法从另一个类/线程重新绘制它。有人知道为什么吗 sscce: import javax.swing.JPanel; 导入javax.swing.Timer; 导入java.awt.Color; 导入java.awt.Dimension; 导入java.awt.Graphics; 导入java.awt.event.ActionEvent; 导入java.awt.ev

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

sscce:

import javax.swing.JPanel;
导入javax.swing.Timer;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.JFrame;
公共类UI扩展了JFrame{
公共静态void main(字符串[]args){
UI myProgram=newui();
myProgram.setVisible(true);
}
公共用户界面(){
此.设置尺寸(新尺寸(500300));
这个.背景(颜色.白色);
此.setDefaultCloseOperation(关闭时退出);
UserPanel p=新的UserPanel(此);
}
公共类UserPanel扩展JPanel实现ActionListener{
专用定时器时间=新定时器(1,此);
私有UI-myFrame;
公共用户面板(UI myFrame){
this.myFrame=myFrame;
this.setSize(myFrame.getSize());
time.start();
}
@凌驾
已执行的公共无效操作(操作事件e){
重新油漆();
}
@凌驾
公共组件(图形g){
超级组件(g);
系统输出打印(“绘制”);
g、 设置颜色(颜色为黑色);
g、 fillRect(this.getWidth()/2,this.getHeight()/2,50,50);
}
}
}
UI类(带有内部类JPanel):

包雨;
导入javax.swing.JPanel;
导入javax.swing.Timer;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.util.ArrayList;
导入java.util.Random;
导入javax.swing.JFrame;
公共类UI扩展了JFrame{
公共用户界面(){
此.设置尺寸(新尺寸(500300));
这个.背景(颜色.白色);
此.setDefaultCloseOperation(关闭时退出);
UserPanel p=新的UserPanel(此);
}
私有类UserPanel扩展JPanel实现ActionListener{
专用定时器时间=新定时器(1,此);
私有UI-myFrame;
private ArrayList rain=new ArrayList();
私人静态最终整数金额=50;
private Random rand=new Random();
公共用户面板(UI myFrame){
this.myFrame=myFrame;
this.setSize(myFrame.getSize());
对于(int i=0;i
画家:

包雨;
导入javax.swing.JPanel;
公共类Painter扩展线程{
私人JPanel p;
公共画家(JPanel p){
这个,p=p;
这个。start();
}
公开募捐{
while(true){
System.out.println(“尝试绘制…”);
p、 重新油漆();
}
}
}
控制台输出:

试着画画

滴答声

试着画画

滴答声

预期产出:

试着画画

绘画

滴答声

试着画画


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

所有Swing应用程序都必须在自己的线程上运行,称为。(希望通过调用方法启动应用程序)。所以,在事件分派线程之外重新绘制组件确实是个坏主意。不要创建
新线程
,而是在
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)
开始


在您的SSCCE之后更新

为了绘制零部件,它必须具有父级。你
UserPanel p=newuserpanel(这个)但您从未将其添加到帧:

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

谢谢您的回答。我现在更改了代码,但似乎仍然不起作用。它仍然没有调用paintComponent(图形g)。我不知道为什么:(facepalm我不敢相信我忘了这个!谢谢你的帮助,伙计,你是最棒的!)
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);
        }
    }
}