1

我正在尝试向 Swing JLabel 和 JTextArea 添加功能,以便:

  • 用户只能在 textarea 中输入 500 个字符(最大)
  • 标签包含一个字符串消息,告诉用户他们还剩下多少个字符(在每次击键或退格之后)
  • 当组件初始化时,标签显示“最多 500 个字符!”
  • 对于键入的前 500 个字符,对于键入的每个键击(a - z、A - Z、0 - 9 和标点符号),标签显示“剩余 x 个字符”,其中x是它们在到达前剩余的字符数最多 500
  • 键入第 500 个字符时,标签显示“剩余 0 个字符”,文本区域不能再键入更多字符
  • 如果用户键入退格按钮 ( KeyEvent.VK_BACK_SPACE),他们会“释放”一个字符,并且计数会增加。因此,如果他们还剩 400 个字符,并且他们键入退格键,则标签现在显示为“剩余 401 个字符”
  • 如果用户突出显示一组字符并对它们执行批量命令(例如退格,或用单个字符替换突出显示的文本),则正确计算剩余字符数并更新标签。因此,如果他们剩余 50 个字符,并且他们突出显示 5 个字母并按退格键,他们现在有“剩余 55 个字符”

我有 90% 的这个功能可以工作,但是有一些错误,并且不知道如何实现上面的最后一项(突出显示文本上的批量命令)。这是我所拥有的:

boolean ignoreInput = false;
int charMax = 500;
JLabel charCntLabel = getLabel();
JTextArea myTextArea = getTextArea();

myTextArea.addKeyListener(new KeyListener() {
    @Override
    public void keyTyped(KeyEvent e) {
        return;
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // If we should be ignoring input then set make sure we
        // enforce max character count and remove the newly typed key.
        if(ignoreInput)
            myTextArea.setText(myTextArea.getText().substring(0,
                myTextArea.getText().length()));
    }

    @Override
    public void keyPressed(KeyEvent e) {
        String charsRemaining = " characters remaining";
        int newLen = 0;

        // The key has just been pressed so Swing hasn't updated
        // the text area with the new KeyEvent.
        int currLen = myTextArea.getText().length();

        // Adjust newLen depending on whether the user just pressed
        // the backspace key or not.
        if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            newLen = currLen - 1;
            ignoreInput = false;
        }
        else
            newLen = currLen + 1;

        if(newLen < 0)
            newLen = 0;

        if(newLen == 0)
            charCntLabel.setText(charMax + " characters maximum!");
        else if(newLen >= 0 && newLen < charMax)
            charCntLabel.setText((charMax - newLen) + charsRemaining);
        else if(newLen >= charMax) {
            ignoreInput = true;
            charCntLabel.setText("0 " + charsRemaining);
        }
    }
});

上面的代码运行良好,但有一些错误:

  • 它不会阻止用户输入超过 500 个字符。当用户输入第 500 个字符时,标签显示“剩余 0 个字符”。但之后您可以继续输入字符,标签保持不变。
  • 如果 textarea 中有 > 500 个字符,并且开始退格,您会看到每个字符都从 textarea(底层模型)中删除,但标签保持不变。但是,一旦您退格到第 500 个字符,并且您退格,标签将开始正确更改,告诉您“剩余 1 个字符”、“剩余 2 个字符”等。所以...
  • 此代码似乎有效,但仅停止工作 > 500 个字符。一旦你回到最大 500 个字符的范围内,它就会再次开始工作。

问题

  1. 有没有更简单的方法来实现这个所需的功能(以及 Swing JTextArea)?我觉得我在这里重新发明了轮子,并且可能有一种“更清洁”的方式来强制执行字符最大值并更新它们各自的标签。
  2. 如果没有,有人能发现我 > 500 字符的错误吗?我整个早上都在看它,正在拔头发。
  3. 最重要的是,我如何实现处理批量命令以突出显示文本的要求?如何在 textarea 中处理文本选择,监听突出显示文本的更改(例如,使用退格按钮删除多个突出显示的字符等),并正确计算剩余字符的新值?

提前致谢。

4

3 回答 3

10

您可以使用DocumentFilter来限制最大大小,查看此文档部分,它有一个您需要的工作示例。

以此为例,我使用了上面示例文件中的组件:

import java.awt.BorderLayout;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

import components.DocumentSizeFilter;

public class Test {

    public static void main(String[] args) {
        new TestFrame().setVisible(true);
    }

    private static class TestFrame extends JFrame{
        private JTextField textField;
        private DefaultStyledDocument doc;
        private JLabel remaningLabel = new JLabel();

        public TestFrame() {
            setLayout(new BorderLayout());

            textField = new JTextField();
            doc = new DefaultStyledDocument();
            doc.setDocumentFilter(new DocumentSizeFilter(500));
            doc.addDocumentListener(new DocumentListener(){
                @Override
                public void changedUpdate(DocumentEvent e) { updateCount();}
                @Override
                public void insertUpdate(DocumentEvent e) { updateCount();}
                @Override
                public void removeUpdate(DocumentEvent e) { updateCount();}
            });
            textField.setDocument(doc);

            updateCount();

            add(textField, BorderLayout.CENTER);
            add(remaningLabel, BorderLayout.SOUTH);

            setLocationRelativeTo(null);
            pack();
        }

        private void updateCount()
        {
            remaningLabel.setText((500 -doc.getLength()) + " characters remaining");
        }
    }
}
于 2012-12-13T16:18:47.597 回答
2

evt.consume(); 在这种情况下会有很大帮助..你不需要使用 DocumentFilter。这是将用户限制在一定长度的一种更简单的方法

private void jTextArea1KeyTyped(java.awt.event.KeyEvent evt) {                                    
    String s=jTextArea1.getText();
   int l=s.length();
   jTextField1.setText(String.valueOf(l));
   int i=10-l;
   jTextField2.setText(String.valueOf(i));
   try{
   if(l>=10){evt.consume();
   }
   }
   catch(Exception w){}

} 
于 2016-10-02T10:31:54.267 回答
1

补充 Ray S. Kan 所说的话:

有一种更简单的方法来限制 JTextArea 的字符,而不必使用 Ray S. Kan 所示的 DocumentFilter,但他的答案的问题是它不会阻止某人粘贴长文本。以下将阻止用户粘贴内容以绕过限制:

@Override
public void keyTyped(KeyEvent e) {
    int max = 25;
    if(text.getText().length() > max+1) {
        e.consume();
        String shortened = text.getText().substring(0, max);
        text.setText(shortened);
    }else if(text.getText().length() > max) {
        e.consume();
    }
}

如果长度不超过最大值,这将阻止按键被按下,但如果超过最大值,它将简单地将文本区域中的字符串替换为较短的字符串。该text变量是 JTextArea 摆动对象。

于 2017-12-04T17:06:02.650 回答