有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java试图在模式对话框中更新JLabel

我有一个包含JLabel的模态对话框。此对话框调用另一个类中执行长时间运行的查找活动的方法。我希望这个查找类更新从模式对话框传递的JLabel

我尝试过在查找过程中从代码循环更新JLabel,也尝试过在计时器中更新JLabel。(我发现当模式对话框运行时,Swing计时器的actionPerformed方法从未被调用。)由于实现了计时器,我将查找过程移动到了一个单独的线程

我的查找工作正常,但直到过程结束,JLabel仍然不会重新绘制。如果有任何帮助,我将不胜感激

以下是相关的方法。DictionaryTuple是一个包含两个字段的POJO:一个列表和一个字符串。只有getter和setter,但dictionaryThread确实可以访问tupleList;请注意,在阅读完成之前,我们不会在此处触摸它

public List<DictionaryTuple> findTuples() {
    tupleList = new ArrayList<DictionaryTuple>();
    Thread dictionaryThread = new Thread(this);  // This is the long-running lookup thread
    dictionaryThread.start();

    progressTimer = new Timer();
    progressTimer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
                       //  progressCaption is updated in dictionaryThread
            synchronized (progressCaption) {
                lblProgress.setText(progressCaption);
            }
            lblProgress.repaint();
            Thread.yield();
        }
    }, 250, 250);

     try {
        dictionaryThread.join();
    } catch (InterruptedException e) {
    } finally {
      progressTimer.cancel();
      lblProgress.setText("");
      progressCaption = "";
    }
    return tupleList;
}

我也尝试过这种变化;在这种情况下,将保留内部run()调用,直到处理完成:

    progressTimer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            synchronized (progressCaption) {
            System.out.println("Fire!");
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Update");
                    lblProgress.setText(progressCaption);
                    lblProgress.repaint();
                }});
            }
        }
    }, 250, 250);

共 (3) 个答案

  1. # 1 楼答案

    这个演示应该会有帮助。如果我通过调用run来运行长作业,与在单独的线程中运行长作业相比,可以看到不同之处

    
        public static void modalDialogTest() {
            JDialog dialog = new JDialog((JFrame)null);
            final JLabel jl = new JLabel("Need some space");
            JButton jb = new JButton ("Click me");
            Timer t = new Timer(1000, new AbstractAction() {
                int it = 0;
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    jl.setText("" + it);
                    jl.repaint();
                    it++;
                }
    
            });
            t.start();
    
            AbstractAction wait = new AbstractAction() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    Runnable r = new Runnable() {
                        public void run() {
                            try {
                                Thread.sleep(10000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    //r.run();
                    new Thread(r).start();
                }
            };
    
            jb.addActionListener(wait);
            dialog.getContentPane().add(jl);
            dialog.getContentPane().add(jb);
            dialog.getContentPane().setLayout(new FlowLayout());
            dialog.pack();
            dialog.setVisible(true);
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        }
    
  2. # 2 楼答案

    您需要准确地向我们显示您将对话框设置为可见的位置是在调用findTuples()方法之前还是之后?这是至关重要的

    建议:

    • 始终在Swing事件线程或EDT(事件调度线程)上更新JLabel
    • 不要使用java。util。更新Swing应用程序组件的计时器
    • 你可以使用javax。摆动计时器来更新Swing组件,但这在这里不起作用,除非您使用它来轮询后台进程
    • 考虑将SwingWorker用于后台线程,然后通过worker的发布/处理方法或添加到SwingWorker的PropertyChangeListener更新JLabel
    • 在将对话框设置为可见之前,在对话框运行时调用所有想要运行的方法
  3. # 3 楼答案

    谢谢大家的建议。我实现的是气垫船,使用SwingWorker

    我的方法所在的Dictionary类现在扩展了SwingWorker。findTuples()方法变成doInBackground()。计时器和我自己的线程代码不再是必需的

    doInBackground()使用属性名为“progress”的publish()提供要在更新的JLabel中显示的文本

    回到对话框代码中,调用涉及创建字典实例,并使用PropertyChangeListener处理JLabel(名为lblProgress)中的更改,以及检测处理何时完成:

    private void myCallingMethod() {
        final Dictionary dictionary = new Dictionary();
    
        dictionary.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent event) {
                List<DictionaryTuple> tupleList;
    
                // Is processing complete?
                if (event.getNewValue() instanceof StateValue
                        && event.getNewValue() == StateValue.DONE) {
                    try {
                        tupleList = dictionary.get();
                        lblProgress.setText(tupleList.size() + " Tuples Found");
                    } catch (Exception e) {
                        JOptionPane.showMessageDialog(
                                null,
                                "Error in processing dictionary: "
                                        + e.getMessage());
                        tupleList = new ArrayList<DictionaryTuple>();
                        lblProgress.setText("");
                    }
    
                    // Process the results.
                    processTuples(tupleList);
    
                } else {
                    // The process isn't done yet.
                    // Is this a request to change lblProgress?
                    if (event.getPropertyName().equals("progress")) {  
                        lblProgress.setText((String) event.getNewValue());
                    }
                }
            }
        });
    
        // Start the dictionary lookup to run asynchronously.
        dictionary.execute();
    }
    

    我学会了不依赖SwingWorker。isDone()来确定SwingWorker的处理是否完成。在我的例子中,PropertyChangeListener在这种状态下被调用了两次:一次是最后一次publish()调用的结果,一次是任务实际完成时