简体   繁体   English

如何实时更新Swing组件

[英]How to update Swing Components in Real Time

I am programming a multiplication app for very large integers, I need to update every sigle step of the multiplication in a Swing component ( I created a JPane extended class with a JTextArea in it, then add it to the JFrame inside a ScrollPane). 我正在为一个非常大的整数编写乘法应用程序,我需要在Swing组件中更新乘法的每个单步操作(我创建了一个带有JTextArea的JPane扩展类,然后将其添加到ScrollPane中的JFrame中)。 The issue is that this Swing component only updates once the multiplication algorithm is done. 问题是该Swing组件仅在乘法算法完成后才更新。 I tried using a Thread that would call repaint method of the Pane every 10 ms, but it did not work. 我尝试使用每10毫秒调用一次Pane的repaint方法的Thread,但是它不起作用。 The next is a sample of the problem. 接下来是问题的样本。

This is the main Frame class: 这是主要的Frame类:

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();
}
}

This is the Console Class 这是控制台类

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");
    }
}

Finally, this is the Calculator class (the one responsible for calling the writing) 最后,这是Calculator类(负责调用写作的类)

public class Calculator {


    private Frame parent;

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

    public void calculate(){
        for (int i = 0; i <= 1000000; i++) {
            parent.writeOnConsole("Iteration "+i);
        }
    }
}

Note that if you run the program, the GUI will freeze until the Calculator class is done with the loop. 请注意,如果您运行该程序,则GUI将冻结,直到用循环完成Calculator类为止。

if you have a layout like a BorderLayout and you want to update it inside the JFrame do as bellow 如果您有一个类似于BorderLayout的布局,并且想在JFrame中更新它,请执行以下操作

JFrame frame = new JFrame();
BorderLayout layout = new BorderLayout();
layout.layoutContainer(frame.getContentPane());// use the frame as the border layout container

else you can use JFrame pack() method. 否则,您可以使用JFrame pack()方法。 The pack method packs the components within the window based on the component's preferred sizes. pack方法根据组件的首选大小在窗口内打包组件。 it's not for updating but it updates the JFrame which is kind of a trick 它不是用于更新,而是更新JFrame,这是一个技巧

JFrame frame = new JFrame();
//change the components dynamically
frame.pack();

or use Container methdod validate(). 或使用Container方法validate()。 Validating a container means laying out its subcomponents. 验证容器意味着布置其子组件。 Layout-related changes, such as setting the bounds of a component, or adding a component to the container. 与布局有关的更改,例如设置组件的边界或将组件添加到容器。

JFrame frame = new JFrame();
Container container = frame.getContentPane();
container.validate();

or if you want to update an specific component use 或者如果您想更新特定的组件用途

Component component = new JPanel();
component.repaint();

If this component is a lightweight component, repaint() method causes a call to this component's paint method as soon as possible . 如果此组件是轻型组件,则repaint()方法将导致尽快调用此组件的paint方法。

or if you want for example numerous changes happen one by one dynamically then you could use the code below which is completely different from the things i said above. 或者,例如,如果您希望动态地进行大量更改,那么可以使用下面的代码,它与我上面所说的完全不同。 for that you could use platform.runlater() inside another thread which deals with everything that is about to change in realtime 为此,您可以在另一个线程中使用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方法以维护每个更改

your Console class would be 您的控制台类将是

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");

    }
  }

and the Calculator class is 而Calculator类是

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();


    }
}

as you can see i used another thread to do the changes 如您所见,我使用了另一个线程来进行更改

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM