DocumentListener与Thread.sleep

3

我希望在写入和删除时能够获得提示,但是在0.5秒延迟后,它会告诉我“您停止了写入/删除”。然而,只有在半秒延迟后才显示该消息,并且才会执行删除或写入操作。

我应该如何正确使用Thread.sleep(500);

我的当前源代码:

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;


public class TextChangedFrame extends JFrame {

    JTextField textField = new JTextField("Put your text here");
    JLabel label = new JLabel("You have written: ");

    public TextChangedFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 100);
        setLayout(new BorderLayout());
        getContentPane().add(textField, BorderLayout.CENTER);
        getContentPane().add(label, BorderLayout.SOUTH);
        textField.getDocument().addDocumentListener(new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                label.setText("I'm writting: " + textField.getText());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {

                }
                label.setText("I stopped writing");
            }

            public void removeUpdate(DocumentEvent e) {
                label.setText("I'm deleting");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {

                }
                label.setText("I stopped deleting");
            }

            public void changedUpdate(DocumentEvent e) {
            }
        });
    }

    public static void main(String[] args) {
        TextChangedFrame frame = new TextChangedFrame();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

永远不要在Swing事件分派线程(EDT)上调用Thread.sleep(...)。除非你想让整个应用程序休眠,否则永远不要这样做。 - Hovercraft Full Of Eels
哦,那我该怎么做呢? - DavidM
我不确定你在问什么。我已经编辑过了,试图澄清问题,但如果您能编辑问题以提供更多细节,那将会非常有帮助。目前看来,您正在询问 thread.sleep(int x) 的作用,它会暂停当前线程正在执行的任何操作,持续 x 毫秒(Thread.sleep(1000) = 1 秒暂停)。 - Azulflame
你到底想做什么?请为我们澄清你的问题。不要假设我们已经了解你的问题。 - Hovercraft Full Of Eels
请使用Swing计时器。 - Hovercraft Full Of Eels
显示剩余3条评论
2个回答

3

再次使用Swing计时器来完成这项工作。每当您进行编辑或删除操作时,请调用Timer的restart()方法重新设置计时器并启动它。如果计时器正在运行,则restart()方法将停止计时器。

     public void insertUpdate(DocumentEvent e) {
        label.setText(EDITING);
        writeDeleteTimer.restart();
     }

例如:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

@SuppressWarnings("serial")
public class TextChangedFrame extends JPanel {

   public static final String STOPPED_EDITING = "No Longer Editing or Deleting";
   private static final String EDITING = "Editing";
   private static final String DELETING = "Deleting";
   private static final int TIMER_DELAY = 500;
   private static final int PREF_W = 400;
   private static final int PREF_H = 100;
   private JTextField textField = new JTextField("Put your text here");
   private JLabel label = new JLabel("You have written: ");
   private ActionListener timerListener = new TimerListener();
   private Timer writeDeleteTimer = new Timer(TIMER_DELAY, timerListener);

   public TextChangedFrame() {
      setLayout(new BorderLayout());
      add(textField, BorderLayout.CENTER);
      add(label, BorderLayout.SOUTH);
      textField.getDocument().addDocumentListener(new DocumentListener() {

         public void insertUpdate(DocumentEvent e) {
            label.setText(EDITING);
            writeDeleteTimer.restart();
         }

         public void removeUpdate(DocumentEvent e) {
            label.setText(DELETING);
            writeDeleteTimer.restart();
         }

         public void changedUpdate(DocumentEvent e) {
         }
      });
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent evt) {
         label.setText(STOPPED_EDITING);
         Timer timer = (Timer) evt.getSource();
         timer.stop();
      }
   }

   private static void createAndShowGui() {
      TextChangedFrame mainPanel = new TextChangedFrame();

      JFrame frame = new JFrame("TextChangedFrame");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

答案已编辑:无需重新创建Timer对象。只需要在Timer对象上调用restart()方法即可,它会停止当前正在运行的Timer。

谢谢!这正是我在寻找的! 它可以正常工作! :) - DavidM
@David:请查看代码的编辑和简化。没有必要每次重新创建计时器,只需调用restart()即可。 - Hovercraft Full Of Eels

2
这个问题比较糟糕,而且不太清楚,所以在问题澄清之前我无法给出确切的答案。
目前看来,您正在使用Thread.sleep(500)使延迟500毫秒。在大多数程序中,这将起作用。 Thread.sleep(int x)暂停(或冻结,取决于你问谁)当前操作x毫秒(在您的情况下为500毫秒)。
在您使用的应用程序中,您正在使用它来暂停文本更改。由于它的位置,它目前冻结了整个swing框,并且没有恢复。
如果您必须使用Thread.sleep(int x),那么我建议您将要使用的文本保存为字符串,然后在更新字符串后更新TextChangedFrame。这样可以让您暂停操作,而不会暂停TextChangedFrame
伪代码:
String oldString = "old string";
String newString = "new string";

// setup your dialog/popup here, with oldString

Thread.sleep(500);

// modify the dialog/popup here, changing oldString to newString

"这样应该可以避免任何冻结问题。(我认为,根据问题和评论,这是您的问题)。
更好的解决方案是使用Swing Timers,就像Hovercraft Full Of Eels他的评论中提到的那样。"

我会尝试使用“Swing计时器”!谢谢 - DavidM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接