Java 如何实时更新Swing组件

Java 如何实时更新Swing组件,java,swing,Java,Swing,我正在为非常大的整数编写一个乘法应用程序,我需要更新Swing组件中乘法的每个单步(我创建了一个JPane扩展类,其中包含一个JTextArea,然后将其添加到滚动窗格中的JFrame)。问题是这个Swing组件只在乘法算法完成后更新。我尝试使用一个线程,每10毫秒调用一次窗格的repaint方法,但没有成功。接下来是问题的一个例子 这是主框架类: import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.e

我正在为非常大的整数编写一个乘法应用程序,我需要更新Swing组件中乘法的每个单步(我创建了一个JPane扩展类,其中包含一个JTextArea,然后将其添加到滚动窗格中的JFrame)。问题是这个Swing组件只在乘法算法完成后更新。我尝试使用一个线程,每10毫秒调用一次窗格的repaint方法,但没有成功。接下来是问题的一个例子

这是主框架类:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Frame extends JFrame implements ActionListener{
private Console console;
private JButton calculate;
private Calculator calculator;


public Frame(){
    console=new Console();
    calculate=new JButton("Calculate");
    calculate.addActionListener(this);
    calculate.setActionCommand("");
    calculator=new Calculator(this);
    this.setLayout(new BorderLayout());
    this.add(console,BorderLayout.CENTER);
    this.add(calculate, BorderLayout.NORTH);
    this.setTitle("Frame");
    this.setVisible(true);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(new Dimension(500,500));
    this.setLocationRelativeTo(null);


}


public void writeOnConsole(String txt){
    console.write(txt);
}


@Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    if(e.getActionCommand().equals("")){
        console.clear();
        calculator.calculate();
    }
}


public static void main(String[] args) {
    new Frame();
}
}
这是控制台类

import java.awt.BorderLayout;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;

public class Console extends JPanel{

    private JTextArea area;


    public Console(){
        this.setBorder(new TitledBorder("Console:"));
        area=new JTextArea();
        this.setLayout(new BorderLayout());
        JScrollPane scroll=new JScrollPane(area);
        this.add(scroll,BorderLayout.CENTER);
    }

    public void clear(){
        area.setText("");
    }
    public void write(String txt){
        area.append(txt+"\n");
    }
}
最后,这是Calculator类(负责调用编写代码的类)

公共类计算器{
私有帧父级;
公共计算器(框架f){
父代=f;
}
公共空间计算(){

对于(int i=0;i如果您有一个类似于
BorderLayout
的布局,并且您希望在JFrame中更新它,请按照下面的步骤进行

JFrame frame = new JFrame();
BorderLayout layout = new BorderLayout();
layout.layoutContainer(frame.getContentPane());// use the frame as the border layout container
否则可以使用JFrame pack()方法。pack方法根据组件的首选大小在窗口中打包组件。它不用于更新,但它会更新JFrame,这是一种技巧

JFrame frame = new JFrame();
//change the components dynamically
frame.pack();
或者使用Container methdod validate()。验证容器意味着布置其子组件。与布局相关的更改,例如设置组件的边界或将组件添加到容器中

JFrame frame = new JFrame();
Container container = frame.getContentPane();
container.validate();
或者,如果要更新特定组件,请使用

Component component = new JPanel();
component.repaint();
如果此组件是轻量级组件,repaint()方法会导致尽快调用此组件的paint方法

或者,如果您希望动态地一个接一个地发生大量更改,那么您可以使用下面的代码,这与我上面所说的完全不同。为此,您可以在另一个线程中使用
platform.runlater()
,该线程实时处理即将更改的所有内容

new Thread(new Runnable() 
    {
    @Override 
    public void run() 
    {

        Platform.runLater(new Runnable()//use platform.runlater if you are using javafx
        {
            @Override 
            public void run() 
            {
                try
                {Thread.sleep(50);}catch(Exception e){}//use it in for loop where changes happen
                //do some realtime change of components
            }
        });

}).start();

尝试使用update方法调用paint方法来维护您的Console类所做的每一项更改

import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;


public class Console extends JPanel{

    private JTextArea area;


    public Console(){
        this.setBorder(new TitledBorder("Console:"));
        area=new JTextArea();
        this.setLayout(new BorderLayout());
        JScrollPane scroll=new JScrollPane(area);
        this.add(scroll,BorderLayout.CENTER);
    }

    public void clear(){
        area.setText("");
    }
    public void write(String txt){

        area.append(txt+" "+"\n");

    }
  }
计算器类是

public class Calculator {


    private Frame parent;

    public Calculator(Frame f){
        parent=f;
    }

    public void calculate(){
        new Thread(new Runnable() {
            @Override 
            public void run() 
            {

                for (int i = 0; i <= 100; i++) {
                    try
                    {
                        Thread.sleep(50);

                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }

                    parent.writeOnConsole("Iteration "+i);
                }

            }   
        }).start();


    }
}
公共类计算器{
私有帧父级;
公共计算器(框架f){
父代=f;
}
公共空间计算(){
新线程(newrunnable()){
@凌驾
公开募捐
{

对于(int i=0;i为什么线程?为什么不使用BigInteger?大整数有多大?您确定任何乘法都需要10毫秒的时间吗?(计算机可以在10毫秒内完成很多工作。)10ms对于GUI更新来说是一个非常严格的循环。首先,如果什么都没有发生,您可能正在阻止/使用EDT,而您的计算正在进行。其次,使用250ms之类的时间,用户真的看不到区别。@SMA实际上是一个assignment,不能使用BigInteger。1)不要阻止EDT(事件调度线程)。GUI将在发生这种情况时“冻结”。有关详细信息和修复方法,请参阅。2)若要更快获得更好的帮助,请发布or。感谢您的回复,刚刚尝试了上述所有操作,但均未达到预期效果。我想解释应用程序的结构,首先是JFrame,其中包含类控制台(从JPanel扩展而来),该类中有一个JTextArea,它位于滚动窗格中。计算的每一步都会生成对JTextArea append方法的调用,我需要Console类在每次append调用后实时更新。所有这些都非常有效。但由于我没有您的代码,我让您大致了解了。将其应用于代码的工作但是如果你想要一些实时的改变(比如在JTextArea中一个接一个地显示每个字符)然后--->我在我的答案中添加了另一个代码,你可以检查它。基本上你必须在另一个线程中实时更改组件。同样,这也有效,但取决于你是否正确地将其应用到代码中。如果你对答案满意,请检查此帖子作为答案(答案左上方的复选标记)我已经为我的问题创建了一个小例子,再次感谢你的帮助,我理解你给我的一些解决方案,并且真的试图让它们发挥作用,但它们没有,可能是我的错。也许你可以检查一下这个例子,给我一些具体的见解?
public class Calculator {


    private Frame parent;

    public Calculator(Frame f){
        parent=f;
    }

    public void calculate(){
        new Thread(new Runnable() {
            @Override 
            public void run() 
            {

                for (int i = 0; i <= 100; i++) {
                    try
                    {
                        Thread.sleep(50);

                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }

                    parent.writeOnConsole("Iteration "+i);
                }

            }   
        }).start();


    }
}