代码之家  ›  专栏  ›  技术社区  ›  Mahdi Ghajary

使用属性更改侦听器更新Swing组件

  •  1
  • Mahdi Ghajary  · 技术社区  · 8 年前

    我第一次使用属性更改监听器,所以我不太熟悉在几个类之间使用它的方式。
    我在Java中编写了一个下载管理器,在类下载中,有像下载大小和sieFuffle等的字段。还有类下载面板,它是GUI,是一个JPant,包含一个JPrimeStBar和几个JCLAP来显示下载的文件数量或文件大小(使用DO)。wnload字段)。
    下载类扩展SwingWorker,并使用httpurlConnection从特定的URL下载给定的文件。
    在下载文件以更新其下载面板时,我实现了属性更改侦听器。问题是jprogressbar被正确地更新了,但是jlabel显示下载的大小和sizeofile并不会通过文件的下载而改变。

    注意,类中不相关的部分和getter/setter被省略,只包括与问题相关的部分。

    属性更改侦听器的实现:

    public class DownloadPanelPropertyListener implements PropertyChangeListener {
    
        Download download;
    
        public DownloadPanelPropertyListener(Download download) {
            this.download = download;
        }
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName()))
                download.getDownloadPanel().getJpb().setValue((Integer) evt.getNewValue());
            else if ("downloadPanel".equals(evt.getPropertyName())) {
                DownloadPanel temp = (DownloadPanel) evt.getNewValue();
                int ds = temp.download.getDownloadedSize();
                int sof = temp.download.getSizeOfFile();
                download.getDownloadPanel().setDownloadedSizeLabel(ds, sof);
            }
        } 
    

    下载面板类代码:

    public class DownloadPanel extends JPanel {
    
        Download download;
        JProgressBar jpb = new JProgressBar(0,100);
        JLabel downloadSpeedLabel;
        JLabel downloadedSizeLabel;
    
        public DownloadPanel (Download d) {
            download = d;
            this.addPropertyChangeListener("downloadPanel",new DownloadPanelPropertyListener(download));
            jpb.setValue( (int) (( (double) download.getDownloadedSize() / (double) download.getSizeOfFile()) * 100)) ;
            jpb.setBounds(100,25,400,10);
            jpb.setIndeterminate(false);
            JLabel progressBarValue = new JLabel("%" + jpb.getValue() + "");
            progressBarValue.setBounds(510,18,25,20);
            add(progressBarValue);
            downloadSpeedLabel = new JLabel (String.format ("%dKbs",download.getDownloadSpeed()));
            downloadedSizeLabel = new JLabel (String.format ("%d MG / %d MG",download.getDownloadedSize(),download.getSizeOfFile()));
            add(downloadSpeedLabel); add(downloadedSizeLabel);
        }  
    

    和类下载:

    public class Download extends SwingWorker<Void,Void> implements Serializable,Runnable {
    
        private transient DownloadPanel downloadPanel = null;
        private transient MainPage mp;
        private String fileName;
        private String hostName;
        private int downloadSpeed;
        private int downloadedSize;
        private int sizeOfFile;
        private int queueIndex;
        private URL url;
    
        public Download (MainPage c,URL url,File f,int index) {
    
            addPropertyChangeListener(new DownloadPanelPropertyListener(this));
            mp = c;
            this.url = url;
            queueIndex = index;
            downloadTime = time;
            fileName = url.getFile();
            hostName = url.getHost();
            sizeOfFile = -1;
            downloadSpeed = 0;
            downloadedSize = 0;
        }
    
        public Void doInBackground () {
            RandomAccessFile file = null;
            InputStream stream = null;
    
            try {
                // Open connection to URL.
                HttpURLConnection connection =
                        (HttpURLConnection) url.openConnection();
    
                // Specify what portion of file to download.
                connection.setRequestProperty("Range",
                        "bytes=" + downloadedSize + "-");
    
                // Connect to server.
                connection.connect();
    
                // Make sure response code is in the 200 range.
                if (connection.getResponseCode() / 100 != 2) {
                    System.out.println("0");
                }
    
                // Check for valid content length.
                int contentLength = connection.getContentLength();
                if (contentLength < 1) {
                    System.out.println("1");
                }
    
          /* Set the size for this download if it
             hasn't been already set. */
                if (sizeOfFile == -1) {
                    sizeOfFile = contentLength;
                }
    
                // Open file and seek to the end of it.
                file = new RandomAccessFile(new File(s.getCurrentDirectory(),getFileName(url)),
                        "rw");
                file.seek(downloadedSize);
    
                stream = connection.getInputStream();
                while (status == CURRENT) {
            /* Size buffer according to how much of the
               file is left to download. */
                    byte buffer[];
                    if (sizeOfFile - downloadedSize > MAX_BUFFER_SIZE) {
                        buffer = new byte[MAX_BUFFER_SIZE];
                    } else {
                        buffer = new byte[sizeOfFile - downloadedSize];
                    }
    
                    // Read from server into buffer.
                    int read = stream.read(buffer);
                    if (read == -1)
                        break;
    
                    // Write buffer to file.
                    file.write(buffer, 0, read);
                    downloadedSize += read;
                    setProgress ( (int) (( (double) getDownloadedSize() / (double) getSizeOfFile()) * 100));
                }
    
          /* Change status to complete if this point was
             reached because downloading has finished. */
                if (status == CURRENT) {
                    status = COMPLETE;
                }
            } catch (Exception e) {
                System.out.println("2");
                e.printStackTrace();
            } finally {
                // Close file.
                if (file != null) {
                    try {
                        file.close();
                    } catch (Exception e) {}
                }
    
                // Close connection to server.
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (Exception e) {}
                }
            }
            return null;
        }
    
        private String getFileName(URL url) {
            String fileName = url.getFile();
            return fileName.substring(fileName.lastIndexOf('/') + 1);
        }
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   Hovercraft Full Of Eels    8 年前

    我看不到您曾经在属性更改侦听器中设置过jLabel的文本,但是已经说过,您不应该这样做,因为它违反了OOP封装。而是:

    • 把你的 DownloadPanel A级 public void setPercentDownload(int value) 方法,在此方法中,设置jProgressBar 和 jLabel的文本通过 setText(...)
    • 在prop change listener中,调用此方法将值传递给GUI。
    • 不要在监听器中设置进度条的值,让视图像我上面提到的那样做。
    • 请确保在属性更改侦听器中侦听newValue==swingWorker.StateValue.Done。发生这种情况时,请致电 get() 在您的工作线程上,这样您就可以捕获后台线程中可能发生的任何异常。
    • 附带问题:只对说“不” null 布局和设定界限。它们使刚性的GUI不适用于所有平台,并且是调试和增强的一个负担。使用布局管理器。

    例如,我的 Minimal, Complete, and Verifiable example (mcve):

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.KeyEvent;
    import java.beans.*;
    import java.io.Serializable;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.*;
    
    public class FooProgress  {
        private static void createAndShowGui() {
            JFrame frame = new JFrame("FooProgress");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(new DownloadPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    class DownloadListener implements PropertyChangeListener {
        private DownloadPanel downloadPanel;
    
        public DownloadListener(DownloadPanel downloadPanel) {
            this.downloadPanel = downloadPanel;
        }
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                int value = (int) evt.getNewValue();
                downloadPanel.setPercentDownload(value);
            } else if ("state".equals(evt.getPropertyName())) {
                if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                    Download download = (Download) evt.getSource();
                    try {
                        download.get();
                    } catch (InterruptedException | ExecutionException e) {
                        // TODO: handle exceptions here
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    @SuppressWarnings("serial")
    class DownloadPanel extends JPanel {
        private static final String PROGRESS_FORMAT = "%03d%%";
        private JProgressBar jpb = new JProgressBar(0, 100);
        private JLabel downloadedSizeLabel = new JLabel(String.format(PROGRESS_FORMAT, 0));
        private DownLoadAction downLoadAction = new DownLoadAction();
    
        public DownloadPanel() {
            JPanel topPanel = new JPanel();
            topPanel.add(new JLabel("Download Progress:"));
            topPanel.add(downloadedSizeLabel);
            JPanel bottomPanel = new JPanel();
            bottomPanel.add(new JButton(downLoadAction));
    
            setLayout(new BorderLayout());        
            add(topPanel, BorderLayout.PAGE_START);
            add(jpb);
            add(bottomPanel, BorderLayout.PAGE_END);
        }
    
        public void setPercentDownload(int value) {
            downloadedSizeLabel.setText(String.format(PROGRESS_FORMAT, value));
            jpb.setValue(value);
            if (value == 100) {
                downLoadAction.setEnabled(true);
            }
        }
    
        private class DownLoadAction extends AbstractAction {
            public DownLoadAction() {
                super("Download");
                putValue(MNEMONIC_KEY, KeyEvent.VK_D);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                setEnabled(false);
                setPercentDownload(0);
                Download download = new Download();
                DownloadListener listener = new DownloadListener(DownloadPanel.this);
                download.addPropertyChangeListener(listener);
                download.execute();
            }
        }
    }
    

    class Download extends SwingWorker<Void, Void> implements Serializable, Runnable {
    
        private static final long SLEEP_TIME = 200;
    
        public Void doInBackground() throws Exception {
            int myProgress = 0;
            while (myProgress < 100) {
                myProgress += (int) (10 * Math.random());
                myProgress = Math.min(myProgress, 100);
                setProgress(myProgress);
                Thread.sleep(SLEEP_TIME);
            }
            return null;
        }
    
    }
    

    将来,您将希望用您的代码创建和发布mcve,这样我们就可以轻松地编译、运行和测试它。您的代码中的文件处理太多,我们目前无法测试。我用thread.sleep替换了90%的代码。