无法从 SwingWorker 类更新 JProgressBar

2024-04-09

我有我的主 GUI 线程,其中有一个 JprogressBar 并正在实现 ProprtyChangeListener。

当按下按钮时,扩展 SwingWorker 的不同类就会启动并执行一系列可能很长的计算。 我需要 A 类中的进度条来根据 B 类中的变量来显示进度。

我的代码如下(我所有失败的尝试可能有点混乱......)

将不胜感激任何帮助。

图形用户界面类:

SignalSimulator signalSimulator = new SignalSimulator(
                path, numOfdataPoints, numOfLocalSpikes,
                    numOfExpSpikes, noiseAmp, slope, offset,
                                    rdbtnSineWave.isSelected());       
signalSimulator.addPropertyChangeListener( new PropertyChangeListener() {
    public void propertyChange(PropertyChangeEvent evt) {
        String property = evt.getPropertyName();
        if ("progress".equals(property)) {
            int progress = (Integer) evt.getNewValue();
            System.out.println("value in PropertChangeListener is: " + progress);
            progressBar.setValue(progress);
        }
    }
});
signalSimulator.execute(); 

计算类:

protected Integer doInBackground() throws Exception {
    if (isSine){
        data = generateSineWave(numOfDataPoints, noiseAmp, offset);
        data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
    } else {
        data = generateLinearSignal(numOfDataPoints, noiseAmp, slope, offset);
        data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
    }
    writeLogFile(path, ".txt", data);
    firePropertyChange("progress", 1, 1);
    setProgress((int)progress);
    publish(progress);
    System.out.println("value in doInBackground is: " + progress);
    return 1;
}

EDIT

原来的问题依然存在。由于某种原因,进度条仍未更新, 我确信,progressBar.setValue(progress) 中的“progress”变量正在更新,但 GUI 中的进度条保持不变(固定为 0) 这是我的新代码:

图形用户界面类:

    SignalSimulator signalSimulator = new SignalSimulator(path, numOfdataPoints, numOfLocalSpikes, numOfExpSpikes, noiseAmp, slope, offset, rdbtnSineWave.isSelected());       
    signalSimulator.addPropertyChangeListener( new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        String property = evt.getPropertyName();

        if ("progress".equals(property)) {
            int progress = (Integer) evt.getNewValue();
             System.out.println("value in PropertChangeListener is: " + progress);
             progressBar.setValue(progress);

        }
      }
    });
    signalSimulator.execute();

SwingWorker 类:

@Override
        protected Integer doInBackground() throws Exception {

            if (isSine){
                data = generateSineWave(numOfDataPoints, noiseAmp, offset);
                data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
            }
            else{
                data = generateLinearSignal(numOfDataPoints, noiseAmp, slope, offset);
                data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
            }

            writeLogFile(path, ".txt", data);

            return 1;}


public double[] generateSineWave(int numOfDataPoints, double noiseAmp, double offset){

            Random rnd = new Random();
            double[] dataArray = new double[numOfDataPoints];           


            for (int i=0;i<numOfDataPoints;i++){

                dataArray[i] =  Math.sin(Math.toRadians(i))+rnd.nextDouble()*noiseAmp+offset;
                progress = ((double)i)/(double)numOfDataPoints*100;

                //firePropertyChange("progress", 1, 1);
                setProgress((int)progress);
                //publish(progress);
                System.out.println("value in doInBackground is: " + progress);
            }

            return dataArray;           

EDIT重写了整个事情,没有额外的(不相关的)代码。我想我在这里遗漏了一些基本的东西,因为它仍然没有更新进度条。

public class ProgressBarTest implements PropertyChangeListener {


    private JFrame frame;
    private JButton btnRun;
    static JProgressBar progressBar = new JProgressBar(0,100);

public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable()  {
            public void run() {
                try {
                    //UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 
                    ProgressBarTest window = new ProgressBarTest();
                    window.frame.setVisible(true);
                    //SignalSimulator signalSimulator = new SignalSimulator();

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

            }
        });
    }

/**
 * Create the application.
 */
public ProgressBarTest() {
    initialize();
}

private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);
    frame.setResizable(false);  

    JProgressBar progressBar = new JProgressBar();
    progressBar.setAlignmentX(Component.RIGHT_ALIGNMENT);
    progressBar.setBounds(0, 252, 444, 20);
    progressBar.setStringPainted(true);
    frame.getContentPane().add(progressBar);


    JButton btnRun = new JButton("Start Long Run");
    btnRun.setBounds(167, 214, 159, 31);
    frame.getContentPane().add(btnRun);
    btnRun.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            longRun();
        }

    } );

}


private void longRun(){

    LongRunner longRunner = new LongRunner(100000);
    longRunner.addPropertyChangeListener(new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {

            if ("progress".equals(evt.getPropertyName())){
                int progress = (int) evt.getNewValue();
                System.out.println("Value in propertyChangeListener: "+progress);
                progressBar.setValue(progress);
            }
        }
    });
    longRunner.execute();
}
@Override
public void propertyChange(PropertyChangeEvent arg0) {
    // TODO Auto-generated method stub

}

}

还有 SwingWorker:

import javax.swing.SwingWorker;


public class LongRunner extends SwingWorker<Integer, Double>{

    int numOfPoints;
    double progress;

    public LongRunner(int numOfPoints) {

        this.numOfPoints = numOfPoints;
        this.progress = 0;
    }

    private void runLong(int bigNum){

        for (int i=0; i< bigNum; i++){

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            progress =  (((double)i*100)/(double)bigNum);
            setProgress((int)progress);
            System.out.println("Value in setProgress: "+progress);

        }

    }
    @Override
    protected Integer doInBackground() throws Exception {

        runLong(numOfPoints);
        return null;
    }

}

我在这里做错了什么?


你正在呼唤doInBackground()直接从您的代码中,类似于调用run()直接在可运行程序中。这意味着您的代码实际上并不是在后台线程上运行,因此您可能会用长时间运行的代码破坏事件线程,从而阻止 Swing GUI 和进度栏更新。

解决方案:不要这样做。称呼execute()当您希望它运行时,在您的工作人员上。

如果您需要进一步的帮助,您首先必须帮助我们。您知道您发布了大量代码,其中大部分与您手头的问题完全无关,而且肯定超出了您应该要求志愿者完成的代码。请删除所有无关的不相关代码,而是创建并发布适当的代码MCVE https://stackoverflow.com/help/mcve.


Edit
您似乎还直接从 EDT 调用代码,这些代码应该留给您的工作线程:

        signalSimulator.execute();

        // ************* all these signalSimulator calls below ***********
        if (rdbtnSineWave.isSelected()) {
           data = signalSimulator.generateSineWave(numOfdataPoints,
                 noiseAmp, offset);
           data = signalSimulator.addAnomalies(data, numOfLocalSpikes,
                 numOfExpSpikes);
        } else { // Linear signal is selected
           data = signalSimulator.generateLinearSignal(numOfdataPoints,
                 noiseAmp, slope, offset);
           data = signalSimulator.addAnomalies(data, numOfLocalSpikes,
                 numOfExpSpikes);
        }

        signalSimulator.writeLogFile(path, ".txt", data);

您似乎也只创建oneworker 对象,这是不正确的,因为您无法重用 SwingWorker 对象。

我建议您仅在需要时创建 SwingWorker 对象,并将需要什么类型的信号的信息传递到其构造函数中。这样,上述方法就可以从它们所属的 SwingWorker 的 doInBackground 方法中调用。

e.g.,

signalSimulator = SignalSimulator(rdbtnSineWave.isSelected())
signalSimulator.addPropertyChangeListener(...);
signalSimulator.execute();

请注意,您发布的代码中还有一些其他重要的不相关问题,但它们必须在其他时间解决,但它们包括使用 null 布局和 setBounds,这几乎总是一个非常糟糕的主意。


Edit

再次澄清一下,您的主要问题是您在 Swing 事件线程上调用长时间运行的代码。仅仅因为方法位于 Worker 类中并不意味着调用它会自动使其在后台线程上运行。保证这一点的唯一方法是从您的内部调用代码doInBackground()方法。同样,您要做的是创建新的工作对象当需要的时候例如,在某个 ActionListener 内部,在创建它时,将其运行所需的所有信息传递给它。然后添加您的 PropertyChangeListener,然后.execute()你的工人。这样做,我敢打赌你的代码会工作得更好。


Edit
例如

import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;

import javax.swing.*;

public class ProgressExampleGui {
   private JPanel mainPanel = new JPanel();
   private JProgressBar progressBar = new JProgressBar();
   private JButton pressMeBtn  = new JButton(new MyAction("Press Me", KeyEvent.VK_P, this));

   public ProgressExampleGui() {
      progressBar.setStringPainted(true);
      progressBar.setString("");

      mainPanel.add(pressMeBtn);
      mainPanel.add(progressBar);
   }

   public void setProgress(int progress) {
      progressBar.setValue(progress);
      progressBar.setString(progress + "%");
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   public void setEnabled(boolean enabled) {
      pressMeBtn.setEnabled(enabled);
   }

   private static void createAndShowGui() {
      ProgressExampleGui progExampleGui = new ProgressExampleGui();

      JFrame frame = new JFrame("Progress Example");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(progExampleGui.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class MyAction extends AbstractAction {
   private ProgressExampleGui gui;

   public MyAction(String name, int mnemonic, ProgressExampleGui gui) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.gui = gui;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      AbstractButton source = (AbstractButton) e.getSource();
      gui.setProgress(0);
      source.setEnabled(false);
      MyWorker myWorker = new MyWorker();
      myWorker.addPropertyChangeListener(new WorkerPropChngListener(gui));
      myWorker.execute();
   }
}

class WorkerPropChngListener implements PropertyChangeListener {

   private ProgressExampleGui gui;

   public WorkerPropChngListener(ProgressExampleGui gui) {
      this.gui = gui;
   }

   @Override
   public void propertyChange(PropertyChangeEvent pcEvt) {
      MyWorker myWorker = (MyWorker) pcEvt.getSource();
      if ("progress".equals(pcEvt.getPropertyName())) {
         int progress = ((Integer)pcEvt.getNewValue()).intValue();
         gui.setProgress(progress);
      }

      if (SwingWorker.StateValue.DONE.equals(pcEvt.getNewValue())) {
         try {
            myWorker.get();
         } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
         }
         gui.setEnabled(true);
      }
   }

}

class MyWorker extends SwingWorker<Void, Void> {
   private static final int MAX_INCR = 8;
   private static final long SLEEP_TIME = 200;
   private static final int MAX_VALUE = 100;
   private int value = 0;
   private Random random = new Random();

   @Override
   protected Void doInBackground() throws Exception {
      while (value < MAX_VALUE) {
         value += random.nextInt(MAX_INCR);
         value = Math.min(value, MAX_VALUE);
         Thread.sleep(SLEEP_TIME);
         setProgress(value);
      }
      return null;
   }
}

Edit
关于你的新代码,你有两个main问题:

看看你的数据输出结果:

Value in setProgress: 0.0
Value in setProgress: 0.001
Value in setProgress: 0.002
Value in setProgress: 0.003
Value in setProgress: 0.004
Value in setProgress: 0.005
Value in setProgress: 0.006
Value in setProgress: 0.007
Value in setProgress: 0.008
Value in setProgress: 0.009
Value in setProgress: 0.01
Value in setProgress: 0.011
Value in setProgress: 0.012
Value in setProgress: 0.013
Value in setProgress: 0.014
Value in setProgress: 0.015
Value in setProgress: 0.016
Value in setProgress: 0.017
Value in setProgress: 0.018
Value in setProgress: 0.019
Value in setProgress: 0.02
Value in setProgress: 0.021
Value in setProgress: 0.022
Value in setProgress: 0.023
Value in setProgress: 0.024
Value in setProgress: 0.025
Value in setProgress: 0.026
Value in setProgress: 0.027
Value in setProgress: 0.028
Value in setProgress: 0.029

按照这个速度,当下一个冰河时代到来时,您的进度值将达到 1,并导致 PropertyChangeListener 和 JProgressBar 发生明显变化。所以首先,改变你的睡眠时间,并将你的大数字改为更合理的数字。

接下来,隐藏重要的变量,特别是 JProgressBar 变量,progressBar。这是在类中声明它并初始化它的位置:

public class ProgressBarTest implements PropertyChangeListener {

   private JFrame frame;
   private JButton btnRun;
   static JProgressBar progressBar = new JProgressBar(0, 100);

附带说明一下,这个变量绝对不应该被声明static,但这不是您当前问题的原因。原因是你事实上重新声明在初始化方法中的其他地方使用相同的变量,然后将这个新对象添加到 GUI 中:

private void initialize() {
  frame = new JFrame();

  // .....

  JProgressBar progressBar = new JProgressBar();

  // .....

  frame.getContentPane().add(progressBar);

请理解,这个新的 ProgressBar 变量引用了一个完全不同的 JProgressBar,因此,如果您提前在类中创建的对象的值,您的 GUI 将不会显示任何内容,因为它正在显示一个完全不同的对象。要解决这个问题,**不要在初始化方法中重新声明和初始化新变量。而是使用在类中创建的对象。

代码的其他问题:您经常使用 null 布局和 setBounds。这将向所有人表明您是一名新手 Swing 程序员,因为这意味着您喜欢创建极其难以升级的死板程序,并且可能在所有系统上看起来都不太好。而是使用布局管理器。例如,这是您的代码,进行了一些更改,所有更改均由注释注明:

import java.awt.*;
import java.awt.event.*;
import java.beans.*;

import javax.swing.*;

//!! no need to implement PropertyChangeListener
//!! public class ProgressBarTest implements PropertyChangeListener {
public class ProgressBarTest2 {
   private JFrame frame;
   private JButton btnRun;

   // !! this shouldn't be static!
   // !! static JProgressBar progressBar = new JProgressBar(0, 100);
   private JProgressBar progressBar = new JProgressBar(0, 100); // !!

   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               UIManager
                     .setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
               ProgressBarTest2 window = new ProgressBarTest2();
               window.frame.setVisible(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
   }

   public ProgressBarTest2() {
      initialize();
   }

   private void initialize() {
      frame = new JFrame();
      // !!frame.setBounds(100, 100, 450, 300);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      //!! frame.getContentPane().setLayout(null); //!! never use null layouts
      frame.setResizable(false);

      // !! don't create a shadowed variable
      // !! JProgressBar progressBar = new JProgressBar();

      progressBar.setAlignmentX(Component.RIGHT_ALIGNMENT);
      //!! progressBar.setBounds(0, 252, 444, 20);
      progressBar.setStringPainted(true);
      //!! frame.getContentPane().add(progressBar);
      frame.getContentPane().add(progressBar, BorderLayout.SOUTH);
      btnRun = new JButton("Start Long Run"); //!! no shadowing
      //!! btnRun.setBounds(167, 214, 159, 31);
      JPanel panel = new JPanel(); //!!
      panel.setPreferredSize(new Dimension(450, 300)); //!!
      panel.setLayout(new GridBagLayout()); //!!
      panel.add(btnRun); //!!
      frame.getContentPane().add(panel, BorderLayout.CENTER); //!!
      btnRun.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            longRun();
         }
      });

      //!!
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   private void longRun() {
    //!! use a more realistic value, one that should show change in listener
      //!! LongRunner longRunner = new LongRunner(100000);
      LongRunner2 longRunner = new LongRunner2(10000);  
      longRunner.addPropertyChangeListener(new PropertyChangeListener() {
         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
               int progress = (int) evt.getNewValue();
               System.out.println("Value in propertyChangeListener: "
                     + progress);
               progressBar.setValue(progress);
            }
         }
      });
      longRunner.execute();
   }

   // !! @Override // !! not needed
   // public void propertyChange(PropertyChangeEvent evt) {
   // }
}

class LongRunner2 extends SwingWorker<Integer, Double> {
   private static final long SLEEP_TIME = 15; // !!
   int numOfPoints;
   double progress;

   public LongRunner2(int numOfPoints) {
      this.numOfPoints = numOfPoints;
      this.progress = 0;
   }

   private void runLong(int bigNum) {
      for (int i = 0; i < bigNum; i++) {
         try {
            // !! quicker turn-over so that our bigNum can change
            // in a realistic way
            // !! Thread.sleep(100);
            Thread.sleep(SLEEP_TIME);// !!
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         progress = (((double) i * 100) / (double) bigNum);
         setProgress((int) progress);
         // !! System.out.println("Value in setProgress: " + progress); //!! This will slow us down
      }
   }

   @Override
   protected Integer doInBackground() throws Exception {
      runLong(numOfPoints);
      return null;
   }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法从 SwingWorker 类更新 JProgressBar 的相关文章

随机推荐

  • 如何将 AutoFixture 自定义应用到从基类继承的任何内容?

    为了干燥我的单元测试 我尝试使用 AutoFixture 作为 IoC 容器来实例化我的被测系统 SUT 在本例中是 ASP NET MVCControllers 因此 我想自定义 AutoFixture 以创建没有自动属性的控制器 我尝试
  • 获取 pandas 列中的第一和第二最高值

    我正在使用 pandas 来分析一些选举结果 我有一个 DF 结果 其中每个选区都有一行 代表各个政党 超过 100 个 的选票的列 In 60 Results columns Out 60 Index Constituency Regio
  • 如何在 Ubuntu 中为 Android 设置 Appium

    我是新来的appium 自动化测试技术 我使用的是运行 Ubuntu Linux 的 PC 我已经搜索过这个主题 但没有得到任何有用的教程 谁能指出我正确的文档 不要通过apt get安装nodejs 这需要sudo权限 如果以sudo用户
  • 如何使用 Mock.Of() 模拟没有默认构造函数的类?

    使用起订量 我需要在现有的基础上创建一个假的class 不是接口 有没有默认的ctor 我可以使用 传统 语法来做到这一点 var fakeResponsePacket new Mock
  • 当绑定属性更改时,ListView 分组不会更新

    我正在使用依赖项属性 GroupDescription 根据列表视图项目源的属性对 WPF 列表视图中的项目进行分组 我的问题是 仅当 GroupDescription 值更改时才会更新分组 而不是在列表视图源中项目的绑定属性更改后分组才会
  • iOS 6 中视图控制器的旋转不正确

    在我的应用程序中 我一直在使用现已弃用的 shouldAutoRotateToFace 方法 现在 当使用 iOS 6 模拟器时 当设备处于横向时 我的所有子视图都会旋转到纵向 有谁知道这可能是什么原因造成的 我已经尝试使用supporte
  • 将 Firebase Analytics 添加到 Instant App

    我正在将现有应用程序转换为 Android Instant App 我已经成功地做到了这一点 我的应用程序以即时应用程序形式运行 我现在面临的问题是关于 Firebase Analytics 当我运行即时应用程序时 出现此错误 E Fire
  • :: 运算符必须与 tolower() 一起使用吗?

    transform mystr begin mystr end mystr begin tolower 我正在使用转换函数使字符串全部小写字母 但即使在编写 using namespace std 之后在我的程序顶部 我收到一大堆错误 当像
  • 如何使用 Python 从网页的检查元素中获取数据

    我想使用 Python 从检查元素获取数据 我可以使用 BeautifulSoup 下载源代码 但现在我需要来自网页的检查元素的文本 如果您能建议我如何去做 我将不胜感激 编辑 我所说的检查元素是指 在谷歌浏览器中 右键单击为我们提供了一个
  • 如何将 Visual Studio 宏值放入预处理器指令中?

    在我的项目中 我需要访问的价值 SolutionDir 运行时的宏 为此 我尝试添加预处理器条目 例如DEBUG ROOT SolutionDir or DEBUG ROOT SolutionDir 但这会由于无效的转义序列而导致各种编译器
  • 代码签名想要使用密钥签名 - 不允许或始终允许但拒绝有效

    我正在尝试构建并存档该应用程序 编译后 会出现一个警告窗口 要求 codesign wants to sign using key my account Name in your keychain 和按钮Always Allow Deny
  • 动态从模块导入类

    我有一堂课叫 my class 放在 my module 我需要导入这个类 我尝试这样做 import importlib result importlib import module my module my class 但它说 Impo
  • Net5 上的 ServiceProcessInstaller 在哪里?

    过去我使用过这些课程安装人员 https learn microsoft com en us dotnet api system configuration install installer view netframework 4 8 服
  • 将 Android 升级到 4.3 后,run-as 提示“程序包未知”

    我有一个简单的脚本 可以将数据库从手机下载到我的电脑 它使用 run as 效果很好 但现在 run as 说 包未知 我的应用程序已安装在设备上 没有任何变化 只是 Android 更新到了 4 3 你也有同样的问题吗 如何绕过这个或解决
  • SwiftUI:停止永远重复的动画

    我想在屏幕上有一个类似 徽章 的东西 当满足条件时 它会从正常尺寸弹到更大 然后反复恢复到正常尺寸 直到不再满足条件 不过 我似乎无法让徽章停止 弹跳 一旦开始 就势不可挡 我尝试过的 我尝试过使用一些动画 但它们可以分为使用 repeat
  • Android 版 OpenCV:示例项目 ClassNotFound 异常

    我正在尝试运行适用于 Android 的 opencv 示例 它不起作用 java lang RuntimeException Unable to instantiate activity ComponentInfo org opencv
  • Rake / Rspec:如何使用 --pattern 抑制/安静/静音显示命令的第一条输出行?

    Problem 如果我跑ServerSpec 基于RSpec 通过Rake使用以下命令之一 rake rake spec rake spec all rake spec
  • 将字符串拆分为数组数组[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我正在写一个iOS App in 斯威夫特 4 2 来自服务器的响应是一个字符串 其值由管道字符 分隔 它包含许多行值
  • Bash:如何仅在完整的行中复制交互式脚本的输入/输出?

    如何实时捕获脚本的输入 输出 例如使用 tee 但逐行而不是逐个字符 我的目标是仅在退格键和自动完成完成处理后 按下 RETURN 键后 捕获输入到脚本交互式提示中的输入 具体来说 我正在尝试为 ssh 创建一个包装器脚本 该脚本创建远程服
  • 无法从 SwingWorker 类更新 JProgressBar

    我有我的主 GUI 线程 其中有一个 JprogressBar 并正在实现 ProprtyChangeListener 当按下按钮时 扩展 SwingWorker 的不同类就会启动并执行一系列可能很长的计算 我需要 A 类中的进度条来根据