1

次のような機能を Swing JLabel および JTextArea に追加しようとしています。

  • ユーザーは、テキストエリアに 500 文字 (最大) しか入力できません
  • ラベルには、残りの文字数をユーザーに伝える文字列メッセージが含まれています (キーストロークまたはバックスペースごとに)。
  • コンポーネントが初期化されると、ラベルに「最大 500 文字!」と表示されます。
  • 入力された最初の 500 文字については、キーストローク (a ~ z、A ~ Z、0 ~ 9、句読点) が入力されるたびに、ラベルに「残り x 文字」と表示されxます。最大 500
  • 500 番目の文字を入力すると、ラベルに「残り 0 文字」と表示され、テキスト領域にそれ以上文字を入力できなくなります。
  • ユーザーがバックスペース ボタン ( KeyEvent.VK_BACK_SPACE) を入力すると、文字が「解放」され、カウントが増加します。したがって、残り 400 文字でバックスペースを入力すると、ラベルは「残り 401 文字」と表示されます。
  • ユーザーが一連の文字を強調表示し、それらに対して一括コマンド (バックスペース、強調表示されたテキストを 1 文字に置き換えるなど) を実行すると、残りの正しい文字数が正しく計算され、ラベルが更新されます。したがって、残り 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 文字」と表示されます。ただし、その後も引き続き文字を入力でき、ラベルは同じままです。
  • テキストエリアに 500 文字を超える文字があり、バックスペースを開始すると、各文字がテキストエリア (基本モデル) から削除されていることがわかりますが、ラベルは同じままです。しかし、500 番目の文字に到達するのに十分なバックスペースを取得すると、ラベルは適切に変更され始め、「残り 1 文字」、「残り 2 文字」などと表示されます。
  • このコードは機能しているように見えますが、500 文字を超えると機能しなくなります。その 500 文字の最大値に戻ると、再び機能し始めます。

質問

  1. この必要な機能を (そして Swing JTextArea のために) 実装する簡単な方法はありますか? ここで車輪を再発明しているように感じ、最大文字数を強制してそれぞれのラベルを更新する「よりクリーンな」方法があるかもしれません。
  2. そうでない場合、500 文字を超えるバグを見つけられる人はいますか? 私は午前中ずっとそれを見ていて、髪を引っ張っています.
  3. 最も重要なのは、強調表示されたテキストへの一括コマンドを処理する要件をどのように実装すればよいですか? テキストエリア内のテキスト選択を渡し、強調表示されたテキストへの変更をリッスンし (たとえば、バックスペース ボタンで複数の強調表示された文字を削除するなど)、残りの文字の新しい値を正しく計算するにはどうすればよいですか?

前もって感謝します。

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 に答える