我是否使用SwingWorker?

我的代码发送http调用时,我希望它更改窗口上的JLabel(基本上显示在http调用结束之前还剩下多少时间)。由于我在这里问过另一个问题,我一直在研究SwingWorkers,但不确定如何使用它。我编写的代码基本上都有一个循环来发送调用,每次定时运行调用需要多长时间,计算剩余时间,然后将其发送到JLabel(注意,JLabel位于不同的位置)。实例化的对象。

大多数SwingWorker示例显示了一个在后台继续运行的函数,不受工作线程的影响(例如,完全基于时间而不是被代码更改的计数器)。如果是这种情况,那么JLabel的更改不是只是工作线程的一部分,因为代码通过新循环->计算时间并进行调用-> alter JLabel运行吗?我可能错了,但是如何通过代码而不是独立线程来更改JLabel?

我的问题之一是,当我最初设置代码时,JLabel中没有任何变化。

这是我的代码:

package transcription.windows;

import javax.swing.*;

import java.awt.*;

import static javax.swing.JFrame.EXIT_ON_CLOSE;

public class PleaseWaitWindow {

    private JLabel pleaseWaitJLabel = new JLabel("Please wait");
    private GridBagConstraints containerGbc = new GridBagConstraints();
    private Container contentPaneContainer = new Container();
    private JFrame pleaseWaitJFrame;

    public JLabel getPleaseWaitJLabel() {
        return pleaseWaitJLabel;
    }

    public JFrame setPleaseWaitWindow() {
        pleaseWaitJFrame = new JFrame();
        contentPaneContainer = setContentPane();
        pleaseWaitJFrame.setContentPane(contentPaneContainer);
        pleaseWaitJFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        pleaseWaitJFrame.setTitle("");
        pleaseWaitJFrame.setSize(350,150);
        pleaseWaitJFrame.setLocationRelativeTo(null);
        pleaseWaitJFrame.setVisible(true);

        return pleaseWaitJFrame;
    }

    private Container setContentPane() {
        containerGbc.insets.bottom = 1;
        containerGbc.insets.top = 2;
        containerGbc.insets.right = 1;
        containerGbc.insets.left = 1;
        containerGbc.weightx = 1;
        containerGbc.weighty = 1;

        contentPaneContainer.setLayout(new GridBagLayout());
        contentPaneContainer.setSize(800,700);
        setPleaseWaitJLabel();

        return contentPaneContainer;
    }

    private void setPleaseWaitJLabel() {
        containerGbc.gridx = 2;
        containerGbc.gridy = 5;
        containerGbc.gridwidth = 2;
        containerGbc.gridheight = 1;
        contentPaneContainer.add(pleaseWaitJLabel,containerGbc);
    }

    public void setJLabelDisplay(String displayTime) {
        pleaseWaitJLabel.setText(displayTime);
    }

    public void closeWindow() {
        pleaseWaitJFrame.dispose();
    }
    }

属于ServiceUpload类的方法:

    public String cuttingLoop(String mpBase64Piece,String jobName,String email) {
        Integer numberOfPiecesMinusEnd = (int) Math.ceil(mpBase64Piece.length() / 500000.0);
        List<String> base64List = new ArrayList<>();

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

            if (mpBase64Piece.length() >= 500000) {
                base64List.add(mpBase64Piece.substring(0,500000));
                mpBase64Piece = mpBase64Piece.substring(500000);
            }

        }
        base64List.add(mpBase64Piece);

        pleaseWaitWindow = new PleaseWaitWindow();
        pleaseWaitWindow.setPleaseWaitWindow();
        for (int n = 0; n < base64List.size(); n++) {
            numberOfLoopsLeft = numberOfPiecesMinusEnd - n;
            Stopwatch stopwatch = null;
            String tag;
            Stopwatch.createStarted();
            if (base64List.get(n) != null) {
                if (n == 0) {
                    tag = "start";
                } else if (n == base64List.size() - 1) {
                    tag = "end";
                } else {
                    tag = "middle";
                }
                stopwatch = Stopwatch.createStarted();
                response = providerupload.executeUploadHttp(base64List.get(n),jobName,tag,email);
                stopwatch.stop();
            }
            long oneLoopTime = stopwatch.elapsed(TimeUnit.SECONDS);
            pleaseWaitWindow.setJLabelDisplay(numberOfLoopsLeft*oneLoopTime+" seconds remaining");
            LOGGER.info("complete");
        }
        pleaseWaitWindow.closeWindow();
        return response;
    }

我的问题之一是上述代码未使用“ SwingWorker”时,代码未显示“ JLabel”。

iCMS 回答:我是否使用SwingWorker?

最好将代码分成职责区域。让我们来看三个:1.工作者(即上传者); 2.显示(即JLabel更新); 3.两者的集成(前两个彼此独立,因此您需要一些东西将它们绑在一起)。

从实际工作中抽象出来,您可以使用标准接口。第一个只是一个Runnable,即不带任何参数也不返回任何东西。第二个是Consumer<String>,因为它需要String(显示)但不返回任何内容。第三个是您的主要控件。

让我们从控件开始吧,因为这很简单:

Consumer<String> display = createDisplay();
Runnable worker = createWorker();
CompletableFuture.runAsync(worker);

这将在一个单独的线程中启动工作程序,这听起来像您想要的。

这是您的上传者:

Consumer<String> display = // tbd,see below
Runnable worker = () -> {
    String[] progress = {"start","middle","finish"};
    for (String pr : progress) {
        display.accept(pr);
        Thread.sleep(1000); // insert your code here
    }
}

请注意,此工作人员确实确实取决于消费者;有点“不干净”,但可以。

现在显示。将其定义为Consumer<String>后,它足够抽象,我们可以在控制台上打印进度。

Consumer<String> display = s -> System.out.printf("upload status: %s%n",s);

但是,您想更新JLabel;这样消费者会看起来像

Consumer<String> display = s -> label.setText(s);
// for your code
s -> pleaseWaitWindow.getPleaseWaitLabel().setText(s);

您的实际问题

因此,如果执行此操作,则会注意到标签文本没有按预期更新。这是因为label.setText(s)在工作程序运行所在的线程中执行;它需要插入到Swing线程中。这就是SwingWorker进入的地方。

SwingWorker有一个progress字段,您可以将其用于标签;它也有一个doInBackground(),它是您的实际上传工作线程。这样你就结束了

class UploadSwingWorker {
    public void doInBackground() {
        for(int i = 0; i < 3; i++) {
            setProgress(i);
            Thread.sleep(1000); // again,your upload code
        }
    }
}

那如何更新您的标签? setProgress引发一个PropertyChangeEvent,您可以拦截;使用带有签名的PropertyChangeListener

void propertyChange(PropertyChangeEvent e)

这是一个功能接口,因此您可以使用lambda来实现此功能

String[] displays = {"start","finish"};
updateLabelListener = e -> {
    int index = ((Integer) e.getNewValue()).intValue(); // the progress you set
    String value = displays[index];
    label.setText(value);
}

,您可以使用

将其添加到SwingWorker
SwingWorker uploadWorker = new UploadSwingWorker();
uploadWorker.addPropertyChangeListener(updateLabelListener);
uploadWorker.execute(); // actually start the worker

更简单

请注意,我本人从未使用过SwingWorker。解决不从工作线程中更新GUI的问题的更简单方法是使用SwingUtilities.invokeLater()调用GUI更新。

回到我最初提出的Consumer<String>,你可以做

    Consumer<String> display = s -> SwingUtilities.invokeLater(
        () -> pleaseWaitWindow.getPleaseWaitLabel().setText(s)
    );

,那应该做。这样,您就可以将工作人员保留在更抽象的Runnable中,并使用常规的调度机制来运行它(例如,ExecutorService.submit()CompletableFuture.runAsync()),同时仍然允许在计算机上更新GUI。同样简单的水平。

本文链接:https://www.f2er.com/1971325.html

大家都在问