Java Jframe is displaying but the contents (Panel) is not showing properly

前端 未结 1 1641
心在旅途
心在旅途 2021-01-27 18:00

I\'ve developed a small application to track my daily work activities, this tool contains two classes:

  1. Executor
  2. UIProgress

My objective was

1条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-27 18:23

    The key is likely in these methods here:

    getWorkedItems ();        
    
    getWorkedTickets ();
    
    getRemainTickets ();    
    

    If they take any time to perform at all, your calling them on the Swing event thread will block the thread and freeze your GUI completely, rendering it unable to draw itself properly. The solution is to call any long-running methods in a background thread, such as a SwingWorker's doInBackground() method, and make Swing calls only on the Swing event thread. Again a SwingWorker would work well for this, and in fact it has its own "bound" progress property that can be used. Within the worker simply call setProgress(value) where value is your int from 0 to 100. Then attach a PropertyChangeListener to the worker so that the GUI can be notified of these changes when the progress property is updated.

    A caveat: be sure to listen for the worker to finish its run so that you can call get() on the worker as this ill allow you to trap and respond to any exceptions that might have been called during its run.

    For example, your code could look something like:

    public void executeTask() {
        progress = new UIProgress();
        progress.prepareGUI();
    
        final SwingWorker myWorker = new SwingWorker() {
            @Override
            protected Void doInBackground() throws Exception {
                // progress.updateProgress (10);
                setProgress(10); // sets the worker's "bound" progress property
                getWorkedItems();
    
                setProgress(30);
                getWorkedTickets();
    
                setProgress(50);
                getRemainTickets();
    
                setProgress(70);
    
                // ... only further background work goes here
                // no direct Swing calls
                return null;
            }
        };
        myWorker.addPropertyChangeListener(new PropertyChangeListener() {
    
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
    
                if ("progress".equals(evt.getPropertyName())) {
                    // if the progress property has been changed
                    // get its value and use it to update the GUI
                    progress.updateProgress((int) evt.getNewValue());
                } else if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
                    // worker is done then here notify the GUI
                    // perhaps call:
                    // jf.postTriagedTicketDetailsDaily();
    
                    // call get() on worker to catch and handle exceptions
                    try {
                        myWorker.get();
                    } catch (InterruptedException | ExecutionException e) {
                        // TODO handle the excpetions here
                        e.printStackTrace();
                    }
                }
            }
        });
        myWorker.execute();
    }
    

    Note: code not tested.

    • Please check out Lesson: Concurrency in Swing
    • Also check out the Swing Tutorials

    If this doesn't solve your problem, then you will likely have to create and post a sscce or a minimal example program/mcve where you condense your code into the smallest bit that still compiles and runs, has no outside dependencies (such as need to link to a database or images), has no extra code that's not relevant to your problem, but still demonstrates your problem.

    For example, this small program demonstrates the above code in a working GUI:

    import java.awt.*;
    import java.awt.event.ActionListener;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.IOException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    
    import javax.swing.*;
    
    public class TestWorker {
        private UIProgress progress;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                new TestWorker().executeTask();
            });
        }
    
        public void executeTask() {
            progress = new UIProgress();
            progress.prepareGUI();
    
            final SwingWorker myWorker = new SwingWorker() {
                @Override
                protected Void doInBackground() throws Exception {
                    // progress.updateProgress (10);
                    setProgress(10); // sets the worker's "bound" progress property
                    getWorkedItems();
    
                    setProgress(30);
                    getWorkedTickets();
    
                    setProgress(50);
                    getRemainTickets();
    
                    setProgress(70);
    
                    TimeUnit.SECONDS.sleep(2);
    
                    // ... only further background work goes here
                    // no direct Swing calls
                    return null;
                }
            };
            myWorker.addPropertyChangeListener(new PropertyChangeListener() {
    
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
    
                    if ("progress".equals(evt.getPropertyName())) {
                        // if the progress property has been changed
                        // get its value and use it to update the GUI
                        progress.updateProgress((int) evt.getNewValue());
                    } else if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
                        // worker is done then here notify the GUI
                        progress.updateProgress(100);
                        // perhaps call:
                        // jf.postTriagedTicketDetailsDaily();
    
                        // call get() on worker to catch and handle exceptions
                        try {
                            myWorker.get();
                        } catch (InterruptedException | ExecutionException e) {
                            // TODO handle the exceptions here
                            e.printStackTrace();
                        }
                    }
                }
            });
            myWorker.execute();
        }
    
        // dummy methods just to demonstrate long-running code
        private void getRemainTickets() {
            mySleep(3);  // emulate long-running code
        }
    
        private void getWorkedTickets() {
            mySleep(4);
        }
    
        private void getWorkedItems() {
            mySleep(2);
        }
    
        private void mySleep(int seconds) {
            try {
                TimeUnit.SECONDS.sleep(seconds);
            } catch (InterruptedException e) {}
        }
    
        @SuppressWarnings("serial")
        private class UIProgress extends JPanel {
            private static final int PREF_W = 400;
            private static final int PREF_H = 100;
            private JProgressBar progressBar = new JProgressBar(0, 100);
            private JLabel statusLabel = new JLabel(" ");
    
            public UIProgress() {
                JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
                statusPanel.add(new JLabel("Status:"));
                statusPanel.add(Box.createHorizontalStrut(4));
                statusPanel.add(statusLabel);            
    
                setLayout(new BorderLayout());
                setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
                add(statusPanel, BorderLayout.PAGE_START);
                add(progressBar, BorderLayout.PAGE_END);
            }
    
            public void prepareGUI() {
                JFrame frame = new JFrame("UI Progress");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(this);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
    
            @Override
            public Dimension getPreferredSize() {
                if (isPreferredSizeSet()) {
                    return super.getPreferredSize();
                }
                return new Dimension(PREF_W, PREF_H);
            }
    
            public void updateProgress(int prog) {
                String text = String.format("Current Progress is %d%%", prog);
                statusLabel.setText(text);
                progressBar.setValue(prog);
            }
    
        }
    }
    

    0 讨论(0)
提交回复
热议问题