jLabel不更改文本,jProgressbar不更新

时间:2017-01-30 16:09:34

标签: java swing event-dispatch-thread

我有JFrameJFrame中包含JDesktopPaneJComboBox,多个JLabelJProgressBar。我面临两个挑战:

  1. 我想通过点击JLabel上的JFrame来更新/更改JButton中某个JInternalFrame中的文字(按钮做了一些计算)。

  2. 点击另一个JButton上的JInternalFrame(该按钮执行一项小任务),我想使用JProgressBar(进度栏位于JFrame })显示完成工作的进度。

  3. 我使用SwingUtilities.invokelater()来执行按钮完成的任务。 我使用NetBeans作为我的IDE。

1 个答案:

答案 0 :(得分:1)

很难知道没有代码会发生什么,但可能是事件调度线程(EDT)被阻止(或终止?),例如通过invokeLater调用代码。 EDT用于更新GUI,不应用于(慢)非GUI相关的计算。有关更多详细信息,请参阅教程事件调度线程及后续内容。

示例(不阻止):

import java.awt.*;
import java.awt.event.ActionEvent;
import java.time.LocalTime;

import javax.swing.*;

public class LabelProgress {

    public static void main(String[] args) {
        LabelProgress main = new LabelProgress();
        SwingUtilities.invokeLater(() -> main.showInternal1());
        SwingUtilities.invokeLater(() -> main.showInternal2());
    }

    private JFrame frame;
    private JLabel label;
    private JDesktopPane desktop;
    private JProgressBar bar;

    private int progress = 0;

    private LabelProgress() {
        label = new JLabel("Label: ");

        desktop = new JDesktopPane();

        bar = new JProgressBar(0, 100);
        bar.setStringPainted(true);

        frame = new JFrame();
        frame.setLayout(new BorderLayout());
        frame.add(label, BorderLayout.BEFORE_FIRST_LINE);
        frame.add(desktop, BorderLayout.CENTER);
        frame.add(bar, BorderLayout.AFTER_LAST_LINE);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(600, 400);
        frame.validate();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void showInternal1() {
        JButton change = new JButton("Change");
        change.addActionListener(this::doChange);

        JInternalFrame internal = new JInternalFrame("Change Label");
        internal.setLayout(new FlowLayout());
        internal.add(change);
        internal.setBounds(20, 20, 200, 150);
        internal.setVisible(true);
        desktop.add(internal);
    }

    private void showInternal2() {
        JButton task = new JButton("Task");
        task.addActionListener(this::doTask);

        JInternalFrame internal = new JInternalFrame("Small Task");
        internal.setLayout(new FlowLayout());
        internal.add(task);
        internal.setBounds(150, 100, 200, 150);
        internal.setVisible(true);
        desktop.add(internal);
    }

    private void doChange(ActionEvent ev) {
        // using a SwingWorker:
        // for demonstration I used an anonymous class, maybe a own class is better
        SwingWorker<LocalTime , Void> worker = new SwingWorker<LocalTime , Void>() {
            @Override
            protected LocalTime doInBackground() throws Exception {
                // not executed on the EDT - just get the current time
                LocalTime someCalculation = LocalTime.now();
                return someCalculation;
            }
            @Override
            protected void done() {
                // executed on EDT
                try {
                    LocalTime resultOfSomeCalculation = get();
                    label.setText("Label: " + resultOfSomeCalculation.toString());

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
        worker.execute();
    }

    private void doTask(ActionEvent ev) {
        // no need to use SwingWorker
        Thread thread = new Thread(this::slowTask);
        thread.start();
    }

    private void slowTask() {
        // not really that slow, just for demonstration
        progress += 10;
        if (progress > 100) progress = 100;

        // and now switching to the EDT
        SwingUtilities.invokeLater(() -> bar.setValue(progress));
    }
}