用来自Java内部类的数据更新进度条

brqmpdu1  于 2023-05-05  发布在  Java
关注(0)|答案(2)|浏览(119)

我有一个主要的类,包含swing组件,它调用了一个次要的类,这个类生成了很多我想显示进度条的东西。我怎样才能做到这一点,而不必把整个代码从次要类带到主要类?
下面是简化的代码:

public class ProgressBar {

    public static void main(String[] args) {
        GUI gui = new GUI();
        gui.showGUI();
    }
}
import javax.swing.*;

public class GUI {
    private JFrame mainFrame;
    
    public void showGUI() {
        mainFrame = new JFrame();
        mainFrame.setSize(222, 222);
        mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        
        Primary primary = new Primary();
        mainFrame.add(primary.getPanel());
        mainFrame.setVisible(true);
    }
}
import javax.swing.*;

public final class Primary {
    private JPanel primaryPanel;
    
    public Primary(){
        createPanel();
    }
    
    public void createPanel() {
         primaryPanel = new JPanel();
         primaryPanel.setSize(333, 333);
         
         JTextArea textArea = new JTextArea();
         Secondary secondary = new Secondary();
         textArea.setText(secondary.writeInfo(11));
         primaryPanel.add(textArea);
         
         JProgressBar progressBar = new JProgressBar();
         primaryPanel.add(progressBar);
         
         primaryPanel.setVisible(true);
    }
    
    public JPanel getPanel(){
        return primaryPanel;
    }
}
public class Secondary {
    private String info;
    public int progress;
    
    public Secondary(){
        info = "";
    }
    
    public String writeInfo(int n){
        for(int i=1; i<=n; i++) {
            info += " bla";
            progress = 100*i/n;
            //System.out.println(progress);
        }
        return info;
    }
}
eimct9ow

eimct9ow1#

因此,有两个问题。
首先,您需要某种方式让Secondary通知Primary进度状态已更改。这可以通过使用observer pattern(在Swing中,这些通常被称为“侦听器”)最容易地实现。
其次,Swing是单线程的,不是线程安全的。
这意味着您不应该使用长时间运行或阻塞操作来阻塞事件调度线程,并且您不应该从事件调度线程上下文外部更新UI或UI所依赖的任何状态。
在这种情况下,最好的解决方案是使用SwingWorker
比如...

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new Primary().getPanel());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public final class Primary {
        private JPanel primaryPanel;

        public Primary() {
            createPanel();
        }

        public void createPanel() {
            primaryPanel = new JPanel(new GridBagLayout());
            primaryPanel.setSize(333, 333);

            JTextArea textArea = new JTextArea(10, 20);
            JProgressBar progressBar = new JProgressBar();

            Secondary secondary = new Secondary(new Secondary.LoadObserver() {
                @Override
                public void progressDidChange(Secondary source, int progress) {
                    progressBar.setValue(progress);
                }

                @Override
                public void informationDidUpdate(Secondary source, String info) {
                    textArea.append(" ");
                    textArea.append(info);
                }
            });

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = gbc.REMAINDER;

            primaryPanel.add(new JScrollPane(textArea), gbc);
            primaryPanel.add(progressBar, gbc);

            primaryPanel.setVisible(true);

            secondary.writeInfo(11);
        }

        public JPanel getPanel() {
            return primaryPanel;
        }
    }

    public class Secondary {
        public interface LoadObserver {
            public void progressDidChange(Secondary source, int progress);

            public void informationDidUpdate(Secondary source, String info);
        }

        private LoadObserver observer;

        public Secondary(LoadObserver observer) {
            this.observer = observer;
        }

        public void writeInfo(int n) {
            SwingWorker<String, String> worker = new SwingWorker<>() {
                @Override
                protected String doInBackground() throws Exception {
                    // Inject a small delay to allow the UI time to load
                    // Demonstration purposes only
                    Thread.sleep(1000);
                    String info = "";
                    for (int i = 1; i <= n; i++) {
                        String data = "bla";
                        publish(data);
                        info += " " + data;
                        setProgress(100 * i / n);
                        // Inject a small delay to allow the UI time for the UI 
                        // to update
                    // Demonstration purposes only
                        Thread.sleep(100);
                    }
                    return info;
                }

                @Override
                protected void process(List<String> chunks) {
                    if (observer == null) {
                        return;
                    }
                    for (String value : chunks) {
                        observer.informationDidUpdate(Secondary.this, value);
                    }
                }
            };
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
                        if (observer == null) {
                            return;
                        }
                        observer.progressDidChange(Secondary.this, worker.getProgress());
                    } else if ("state".equalsIgnoreCase(evt.getPropertyName())) {
                        switch (worker.getState()) {
                            case DONE:
                                // Oppurtunity to notify oberser that work has
                                // been completed
                                break;
                        }
                    }
                }
            });
            worker.execute();
        }
    }
}
li9yvcax

li9yvcax2#

您不需要将整个代码从Primary带到Secondary类。您可以将ProgressBar传递给Constructor中的Secondary类,并根据您的逻辑从那里更新它。

Secondary secondary = new Secondary(progressBar);

但是,根据您在Secondary类中实现的逻辑,这可能与Single Responsibility Principle相反。因此,您还可以实现Observer Pattern,并在每次需要更新进度时从Secondary类通知Primary类。

相关问题