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